├── .gitignore ├── README.md ├── xiecc_rtmp.h ├── test.c ├── flv.c └── xiecc_rtmp.c /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Libraries 8 | *.lib 9 | *.a 10 | 11 | # Shared objects (inc. Windows DLLs) 12 | *.dll 13 | *.so 14 | *.so.* 15 | *.dylib 16 | 17 | # Executables 18 | *.exe 19 | *.out 20 | *.app 21 | *.i*86 22 | *.x86_64 23 | *.hex 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # flvmuxer 2 | a mux tool for mux H.264 NAL Video Data with ADTS-AAC RAW Audio Data write to a flv file or publish RTMP Server with librtmp 3 | # How to install ? 4 | 1. you must install rtmpdump firstly if you want to publish stream to RTMP Server 5 | 2. then `gcc -o name xiecc_rtmp.c librtmp.a` 6 | 7 | If you just want to mux to flv file, There's no need to install rtmpdump. 8 | just run `gcc -o name flv.c` 9 | 10 | If it can help you a little, I'll be glad . 11 | 12 | -------------------------------------------------------------------------------- /xiecc_rtmp.h: -------------------------------------------------------------------------------- 1 | #ifndef _XIECC_RTMP_H_ 2 | #define _XIECC_RTMP_H_ 3 | #include 4 | 5 | #ifdef __cplusplus 6 | extern "C"{ 7 | #endif 8 | 9 | #define RTMP_STREAM_PROPERTY_PUBLIC 0x00000001 10 | #define RTMP_STREAM_PROPERTY_ALARM 0x00000002 11 | #define RTMP_STREAM_PROPERTY_RECORD 0x00000004 12 | 13 | // @brief alloc function 14 | // @param [in] url : RTMP URL, rtmp://127.0.0.1/live/xxx 15 | // @return : rtmp_sender handler 16 | void *rtmp_sender_alloc(const char *url); //return handle 17 | 18 | // @brief start publish 19 | // @param [in] rtmp_sender handler 20 | // @param [in] flag stream falg 21 | // @param [in] ts_us timestamp in us 22 | // @return : 0: OK; others: FAILED 23 | int rtmp_sender_start_publish(void *handle, uint32_t flag, int64_t ts_us); 24 | 25 | 26 | // @brief set stream property 27 | // @param [in] rtmp_sender handler 28 | // @param [in] flag stream_property bits 29 | // @param [in] ext extern params in json 30 | // @return : 0: OK; others: FAILED 31 | int rtmp_sender_set_stream_property(void *handle, uint32_t flag, const char *ext); 32 | 33 | // @brief stop publish 34 | // @param [in] rtmp_sender handler 35 | // @return : 0: OK; others: FAILED 36 | int rtmp_sender_stop_publish(void *handle); 37 | 38 | //@brief tell the server start record current stream 39 | //@param handle rtmp_sender handle 40 | int rtmp_sender_start_record(void *handle); 41 | 42 | //@brief tell the server stop record current stream 43 | //@param handle rtmp_sender handle 44 | int rtmp_sender_stop_record(void *handle); 45 | // @brief send audio frame 46 | // @param [in] rtmp_sender handler 47 | // @param [in] data : AACAUDIODATA 48 | // @param [in] size : AACAUDIODATA size 49 | // @param [in] dts_us : decode timestamp of frame 50 | int rtmp_sender_write_audio_frame(void *handle, 51 | uint8_t *data, 52 | int size, 53 | uint64_t dts_us, 54 | uint32_t abs_ts); 55 | 56 | // @brief send video frame, now only H264 supported 57 | // @param [in] rtmp_sender handler 58 | // @param [in] data : video data, (Full frames are required) 59 | // @param [in] size : video data size 60 | // @param [in] dts_us : decode timestamp of frame 61 | // @param [in] key : key frame indicate, [0: non key] [1: key] 62 | int rtmp_sender_write_video_frame(void *handle, 63 | uint8_t *data, 64 | int size, 65 | uint64_t dts_us, 66 | int key, 67 | uint32_t abs_ts); 68 | 69 | // @brief free rtmp_sender handler 70 | // @param [in] rtmp_sender handler 71 | void rtmp_sender_free(void *handle); 72 | 73 | #ifdef __cplusplus 74 | } 75 | #endif 76 | #endif 77 | -------------------------------------------------------------------------------- /test.c: -------------------------------------------------------------------------------- 1 | #include "soooner_rtmp.h" 2 | #include 3 | #include 4 | #include 5 | #define AAC_ADTS_HEADER_SIZE 7 6 | static uint32_t find_start_code(uint8_t *buf, uint32_t zeros_in_startcode) 7 | { 8 | uint32_t info; 9 | uint32_t i; 10 | 11 | info = 1; 12 | if ((info = (buf[zeros_in_startcode] != 1)? 0: 1) == 0) 13 | return 0; 14 | 15 | for (i = 0; i < zeros_in_startcode; i++) 16 | if (buf[i] != 0) 17 | { 18 | info = 0; 19 | break; 20 | }; 21 | 22 | return info; 23 | } 24 | 25 | uint8_t * get_nal(uint32_t *len, uint8_t **offset, uint8_t *start, uint32_t total) 26 | { 27 | uint32_t info; 28 | uint8_t *q ; 29 | uint8_t *p = *offset; 30 | *len = 0; 31 | 32 | while(1) { 33 | info = find_start_code(p, 3); 34 | if (info == 1) 35 | break; 36 | p++; 37 | if ((p - start) >= total) 38 | return NULL; 39 | } 40 | q = p + 4; 41 | p = q; 42 | while(1) { 43 | info = find_start_code(p, 3); 44 | if (info == 1) 45 | break; 46 | p++; 47 | if ((p - start) >= total) 48 | return NULL; 49 | } 50 | 51 | *len = (p - q); 52 | *offset = p; 53 | return q; 54 | } 55 | uint8_t *get_adts(uint32_t *len, uint8_t **offset, uint8_t *start, uint32_t total) 56 | { 57 | uint8_t *p = *offset; 58 | uint32_t frame_len_1; 59 | uint32_t frame_len_2; 60 | uint32_t frame_len_3; 61 | uint32_t frame_length; 62 | 63 | if (total < AAC_ADTS_HEADER_SIZE) { 64 | return NULL; 65 | } 66 | if ((p - start) >= total) { 67 | return NULL; 68 | } 69 | 70 | if (p[0] != 0xff) { 71 | return NULL; 72 | } 73 | if ((p[1] & 0xf0) != 0xf0) { 74 | return NULL; 75 | } 76 | frame_len_1 = p[3] & 0x03; 77 | frame_len_2 = p[4]; 78 | frame_len_3 = (p[5] & 0xe0) >> 5; 79 | frame_length = (frame_len_1 << 11) | (frame_len_2 << 3) | frame_len_3; 80 | *offset = p + frame_length; 81 | *len = frame_length; 82 | return p; 83 | } 84 | 85 | 86 | 87 | int main() 88 | { 89 | 90 | void*p = rtmp_sender_alloc("rtmp://127.0.0.1:1935/live/ddd"); //return handle 91 | rtmp_sender_start_publish(p, 0, 0); 92 | int fd = open("cms.264", O_RDONLY); 93 | uint8_t * buf = malloc(3 *1024 * 1024); 94 | uint32_t total; 95 | total = read(fd, buf, (1024*1024 *3)); 96 | close(fd); 97 | int aacfd = open("audiotest.aac", O_RDONLY); 98 | uint8_t * audio_buf = malloc(1 *1024 * 1024); 99 | uint32_t audio_total; 100 | audio_total = read(aacfd, audio_buf, (1024*1024 *3)); 101 | close(aacfd); 102 | uint8_t *buf_offset = buf; 103 | uint8_t *audio_buf_offset = audio_buf; 104 | uint32_t len; 105 | uint32_t audio_len; 106 | uint8_t *p_video ; 107 | uint8_t *pp; 108 | uint8_t *p_audio; 109 | uint32_t audio_ts = 0; 110 | uint32_t ts = 0; 111 | uint32_t len_1; 112 | uint32_t len_2; 113 | while (1) { 114 | p_audio = get_adts(&audio_len, &audio_buf_offset, audio_buf, audio_total); 115 | if (p_audio == NULL){ 116 | audio_buf_offset = audio_buf; 117 | continue; 118 | } 119 | rtmp_sender_write_audio_frame(p, p_audio, audio_len, audio_ts); 120 | 121 | p_video = get_nal(&len, &buf_offset, buf, total); 122 | if (p_video == NULL) { 123 | buf_offset = buf; 124 | continue; 125 | } 126 | printf("%x %d\n", p_video[0], len); 127 | if (p_video[0] == 0x67) { 128 | pp = get_nal(&len_1, &buf_offset, buf, total); 129 | printf("%x %d\n", pp[0], len_1); 130 | pp = get_nal(&len_2, &buf_offset, buf, total); 131 | printf("%x %d\n", pp[0], len_2); 132 | uint8_t temp = len + len_1 + len_2 + 12; 133 | printf("temp %d\n", temp); 134 | rtmp_sender_write_video_frame(p, p_video - 4, temp, ts, 0); 135 | } 136 | else 137 | rtmp_sender_write_video_frame(p, p_video - 4, len + 4, ts, 0); 138 | ts += 50; 139 | audio_ts += 50; 140 | usleep(50 * 1000); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /flv.c: -------------------------------------------------------------------------------- 1 | /* 2 | * A H264/AAC TO FLV implementation 3 | * 4 | * Copyright (C) 2014 rainfly123 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 | * 20 | */ 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | static uint32_t find_start_code(uint8_t *buf, uint32_t zeros_in_startcode) 27 | { 28 | uint32_t info; 29 | uint32_t i; 30 | 31 | info = 1; 32 | if ((info = (buf[zeros_in_startcode] != 1)? 0: 1) == 0) 33 | return 0; 34 | 35 | for (i = 0; i < zeros_in_startcode; i++) 36 | if (buf[i] != 0) 37 | { 38 | info = 0; 39 | break; 40 | }; 41 | 42 | return info; 43 | } 44 | 45 | uint8_t * get_nal(uint32_t *len, uint8_t **offset, uint8_t *start, uint32_t total) 46 | { 47 | uint32_t info; 48 | uint8_t *q ; 49 | uint8_t *p = *offset; 50 | *len = 0; 51 | 52 | while(1) { 53 | info = find_start_code(p, 3); 54 | if (info == 1) 55 | break; 56 | p++; 57 | if ((p - start) >= total) 58 | return NULL; 59 | } 60 | q = p + 4; 61 | p = q; 62 | while(1) { 63 | info = find_start_code(p, 3); 64 | if (info == 1) 65 | break; 66 | p++; 67 | if ((p - start) >= total) 68 | return NULL; 69 | } 70 | 71 | *len = (p - q); 72 | *offset = p; 73 | return q; 74 | } 75 | 76 | #define AAC_ADTS_HEADER_SIZE 7 77 | #define FLV_TAG_HEAD_LEN 11 78 | #define FLV_PRE_TAG_LEN 4 79 | 80 | typedef struct { 81 | uint8_t audio_object_type; 82 | uint8_t sample_frequency_index; 83 | uint8_t channel_configuration; 84 | }AudioSpecificConfig; 85 | 86 | AudioSpecificConfig gen_config(uint8_t *frame) 87 | { 88 | AudioSpecificConfig config = {0, 0, 0}; 89 | 90 | if (frame == NULL) { 91 | return config; 92 | } 93 | config.audio_object_type = (frame[2] & 0xc0) >> 6; 94 | config.sample_frequency_index = (frame[2] & 0x3c) >> 2; 95 | config.channel_configuration = (frame[3] & 0xc0) >> 6; 96 | return config; 97 | } 98 | 99 | uint8_t gen_audio_tag_header(AudioSpecificConfig config) 100 | { 101 | uint8_t soundType = config.channel_configuration - 1; //0 mono, 1 stero 102 | uint8_t soundRate = 0; 103 | uint8_t val = 0; 104 | 105 | 106 | switch (config.sample_frequency_index) { 107 | case 10: { //11.025k 108 | soundRate = 1; 109 | break; 110 | } 111 | case 7: { //22k 112 | soundRate = 2; 113 | break; 114 | } 115 | case 4: { //44k 116 | soundRate = 3; 117 | break; 118 | } 119 | default: 120 | { 121 | return val; 122 | } 123 | } 124 | val = 0xA0 | (soundRate << 2) | 0x02 | soundType; 125 | return val; 126 | } 127 | 128 | uint8_t *get_adts(uint32_t *len, uint8_t **offset, uint8_t *start, uint32_t total) 129 | { 130 | uint8_t *p = *offset; 131 | uint32_t frame_len_1; 132 | uint32_t frame_len_2; 133 | uint32_t frame_len_3; 134 | uint32_t frame_length; 135 | 136 | if (total < AAC_ADTS_HEADER_SIZE) { 137 | return NULL; 138 | } 139 | if ((p - start) >= total) { 140 | return NULL; 141 | } 142 | 143 | if (p[0] != 0xff) { 144 | return NULL; 145 | } 146 | if ((p[1] & 0xf0) != 0xf0) { 147 | return NULL; 148 | } 149 | frame_len_1 = p[3] & 0x03; 150 | frame_len_2 = p[4]; 151 | frame_len_3 = (p[5] & 0xe0) >> 5; 152 | frame_length = (frame_len_1 << 11) | (frame_len_2 << 3) | frame_len_3; 153 | *offset = p + frame_length; 154 | *len = frame_length; 155 | return p; 156 | } 157 | 158 | 159 | int main(int argc, char **argv) 160 | { 161 | int fd = open("cms.264", O_RDONLY); 162 | 163 | uint8_t * buf = malloc(3 *1024 * 1024); 164 | uint32_t total; 165 | total = read(fd, buf, (1024*1024 *3)); 166 | close(fd); 167 | uint8_t *buf_offset = buf; 168 | 169 | #if 0 170 | uint8_t *nall; 171 | uint32_t len; 172 | while (1) { 173 | nall = get_nal(&len, &buf_offset, buf, total); 174 | printf("%d %x\n", len, nall[0]); 175 | } 176 | #endif 177 | int aacfd = open("audiotest.aac", O_RDONLY); 178 | uint8_t * audio_buf = malloc(3 *1024 * 1024); 179 | uint32_t audio_total; 180 | audio_total = read(aacfd, audio_buf, (1024*1024 *3)); 181 | close(aacfd); 182 | uint8_t *audio_buf_offset = audio_buf; 183 | uint32_t adts_len; 184 | #if 0 185 | while (1) { 186 | char *audio_t = get_adts(&adts_len, &audio_buf_offset, audio_buf, audio_total); 187 | if (audio_t) { 188 | printf("%d %x\n", adts_len, (uint8_t)audio_t[0]); 189 | AudioSpecificConfig config = gen_config(audio_t); 190 | printf("profile:%d sample:%d channel:%d\n", config.audio_object_type, \ 191 | config.sample_frequency_index, config.channel_configuration); 192 | } 193 | else break; 194 | } 195 | #endif 196 | 197 | #if 1 198 | int flv_file = open("a.flv", O_WRONLY|O_CREAT, 0666); 199 | uint8_t flv_header[13] = {0x46, 0x4c, 0x56, 0x01, 0x05, 0x00, 0x00, 0x00, 0x09, \ 200 | 0x00, 0x00,0x00,0x00}; 201 | write(flv_file, flv_header, sizeof(flv_header)); 202 | uint32_t start_time = RTMP_GetTime(); 203 | uint32_t nal_len; 204 | uint32_t nal_len_n; 205 | uint8_t *nal; 206 | uint8_t *nal_n; 207 | uint8_t *output ; 208 | uint32_t offset = 0; 209 | uint32_t body_len; 210 | uint32_t ts = 0; 211 | uint32_t audio_ts = 0; 212 | uint32_t output_len; 213 | uint8_t *audio_frame; 214 | uint8_t audio_seq_set = 0; 215 | static AudioSpecificConfig config; 216 | while (1) { 217 | //ts = RTMP_GetTime() - start_time; 218 | //Audio OUTPUT 219 | offset = 0; 220 | audio_frame = get_adts(&adts_len, &audio_buf_offset, audio_buf, audio_total); 221 | if (audio_frame == NULL) break; 222 | if (audio_seq_set == 0) { 223 | config = gen_config(audio_frame); 224 | body_len = 2 + 2; //AudioTagHeader + AudioSpecificConfig 225 | output_len = body_len + FLV_TAG_HEAD_LEN + FLV_PRE_TAG_LEN; 226 | output = malloc(output_len); 227 | // flv tag header 228 | output[offset++] = 0x08; //tagtype video 229 | output[offset++] = (uint8_t)(body_len >> 16); //data len 230 | output[offset++] = (uint8_t)(body_len >> 8); //data len 231 | output[offset++] = (uint8_t)(body_len); //data len 232 | output[offset++] = (uint8_t)(audio_ts >> 16); //time stamp 233 | output[offset++] = (uint8_t)(audio_ts >> 8); //time stamp 234 | output[offset++] = (uint8_t)(audio_ts); //time stamp 235 | output[offset++] = (uint8_t)(audio_ts >> 24); //time stamp 236 | output[offset++] = 0x00; //stream id 0 237 | output[offset++] = 0x00; //stream id 0 238 | output[offset++] = 0x00; //stream id 0 239 | 240 | //flv AudioTagHeader 241 | output[offset++] = gen_audio_tag_header(config); // sound format aac 242 | output[offset++] = 0x00; //aac sequence header 243 | 244 | //flv VideoTagBody --AudioSpecificConfig 245 | uint8_t audio_object_type = config.audio_object_type + 1; 246 | output[offset++] = (audio_object_type << 3) | (config.sample_frequency_index >> 1); 247 | output[offset++] = ((config.sample_frequency_index & 0x01) << 7) \ 248 | | (config.channel_configuration << 3) ; 249 | uint32_t fff = body_len + FLV_TAG_HEAD_LEN; 250 | output[offset++] = (uint8_t)(fff >> 24); //data len 251 | output[offset++] = (uint8_t)(fff >> 16); //data len 252 | output[offset++] = (uint8_t)(fff >> 8); //data len 253 | output[offset++] = (uint8_t)(fff); //data len 254 | 255 | write(flv_file, output, output_len); 256 | free(output); 257 | 258 | audio_seq_set = 1; 259 | }else 260 | { 261 | body_len = 2 + adts_len - AAC_ADTS_HEADER_SIZE; // remove adts header + AudioTagHeader 262 | output_len = body_len + FLV_TAG_HEAD_LEN + FLV_PRE_TAG_LEN; 263 | output = malloc(output_len); 264 | // flv tag header 265 | output[offset++] = 0x08; //tagtype video 266 | output[offset++] = (uint8_t)(body_len >> 16); //data len 267 | output[offset++] = (uint8_t)(body_len >> 8); //data len 268 | output[offset++] = (uint8_t)(body_len); //data len 269 | output[offset++] = (uint8_t)(audio_ts >> 16); //time stamp 270 | output[offset++] = (uint8_t)(audio_ts >> 8); //time stamp 271 | output[offset++] = (uint8_t)(audio_ts); //time stamp 272 | output[offset++] = (uint8_t)(audio_ts >> 24); //time stamp 273 | output[offset++] = 0x00; //stream id 0 274 | output[offset++] = 0x00; //stream id 0 275 | output[offset++] = 0x00; //stream id 0 276 | 277 | //flv AudioTagHeader 278 | output[offset++] = gen_audio_tag_header(config); // sound format aac 279 | output[offset++] = 0x01; //aac raw data 280 | 281 | //flv VideoTagBody --raw aac data 282 | memcpy(output + offset, audio_frame + AAC_ADTS_HEADER_SIZE,\ 283 | (adts_len - AAC_ADTS_HEADER_SIZE)); //H264 sequence parameter set 284 | //previous tag size 285 | uint32_t fff = body_len + FLV_TAG_HEAD_LEN; 286 | offset += (adts_len - AAC_ADTS_HEADER_SIZE); 287 | output[offset++] = (uint8_t)(fff >> 24); //data len 288 | output[offset++] = (uint8_t)(fff >> 16); //data len 289 | output[offset++] = (uint8_t)(fff >> 8); //data len 290 | output[offset++] = (uint8_t)(fff); //data len 291 | write(flv_file, output, output_len); 292 | free(output); 293 | audio_ts += 100; 294 | 295 | } 296 | 297 | 298 | 299 | //Video OUTPUT 300 | offset = 0; 301 | nal = get_nal(&nal_len, &buf_offset, buf, total); 302 | if (nal == NULL) break; 303 | if (nal[0] == 0x67) { 304 | nal_n = get_nal(&nal_len_n, &buf_offset, buf, total); //get pps 305 | body_len = nal_len + nal_len_n + 16; 306 | output_len = body_len + FLV_TAG_HEAD_LEN + FLV_PRE_TAG_LEN; 307 | output = malloc(output_len); 308 | // flv tag header 309 | output[offset++] = 0x09; //tagtype video 310 | output[offset++] = (uint8_t)(body_len >> 16); //data len 311 | output[offset++] = (uint8_t)(body_len >> 8); //data len 312 | output[offset++] = (uint8_t)(body_len); //data len 313 | output[offset++] = (uint8_t)(ts >> 16); //time stamp 314 | output[offset++] = (uint8_t)(ts >> 8); //time stamp 315 | output[offset++] = (uint8_t)(ts); //time stamp 316 | output[offset++] = (uint8_t)(ts >> 24); //time stamp 317 | output[offset++] = 0x00; //stream id 0 318 | output[offset++] = 0x00; //stream id 0 319 | output[offset++] = 0x00; //stream id 0 320 | 321 | //flv VideoTagHeader 322 | output[offset++] = 0x17; //key frame, AVC 323 | output[offset++] = 0x00; //avc sequence header 324 | output[offset++] = 0x00; //composit time ?????????? 325 | output[offset++] = 0x00; // composit time 326 | output[offset++] = 0x00; //composit time 327 | 328 | //flv VideoTagBody --AVCDecoderCOnfigurationRecord 329 | output[offset++] = 0x01; //configurationversion 330 | output[offset++] = nal[1]; //avcprofileindication 331 | output[offset++] = nal[2]; //profilecompatibilty 332 | output[offset++] = nal[3]; //avclevelindication 333 | output[offset++] = 0xff; //reserved + lengthsizeminusone 334 | output[offset++] = 0xe1; //numofsequenceset 335 | output[offset++] = (uint8_t)(nal_len >> 8); //sequence parameter set length high 8 bits 336 | output[offset++] = (uint8_t)(nal_len); //sequence parameter set length low 8 bits 337 | memcpy(output + offset, nal, nal_len); //H264 sequence parameter set 338 | offset += nal_len; 339 | output[offset++] = 0x01; //numofpictureset 340 | output[offset++] = (uint8_t)(nal_len_n >> 8); //picture parameter set length high 8 bits 341 | output[offset++] = (uint8_t)(nal_len_n); //picture parameter set length low 8 bits 342 | memcpy(output + offset, nal_n, nal_len_n); //H264 picture parameter set 343 | 344 | //no need set pre_tag_size ,RTMP NO NEED 345 | // flv test 346 | offset += nal_len_n; 347 | uint32_t fff = body_len + FLV_TAG_HEAD_LEN; 348 | output[offset++] = (uint8_t)(fff >> 24); //data len 349 | output[offset++] = (uint8_t)(fff >> 16); //data len 350 | output[offset++] = (uint8_t)(fff >> 8); //data len 351 | output[offset++] = (uint8_t)(fff); //data len 352 | write(flv_file, output, output_len); 353 | //RTMP Send out 354 | free(output); 355 | continue; 356 | } 357 | if (nal[0] == 0x06) 358 | { //do nothin 359 | } 360 | 361 | if (nal[0] == 0x65) 362 | { 363 | ts += 170; 364 | body_len = nal_len + 5 + 4; //flv VideoTagHeader + NALU length 365 | output_len = body_len + FLV_TAG_HEAD_LEN + FLV_PRE_TAG_LEN; 366 | output = malloc(output_len); 367 | // flv tag header 368 | output[offset++] = 0x09; //tagtype video 369 | output[offset++] = (uint8_t)(body_len >> 16); //data len 370 | output[offset++] = (uint8_t)(body_len >> 8); //data len 371 | output[offset++] = (uint8_t)(body_len); //data len 372 | output[offset++] = (uint8_t)(ts >> 16); //time stamp 373 | output[offset++] = (uint8_t)(ts >> 8); //time stamp 374 | output[offset++] = (uint8_t)(ts); //time stamp 375 | output[offset++] = (uint8_t)(ts >> 24); //time stamp 376 | output[offset++] = 0x00; //stream id 0 377 | output[offset++] = 0x00; //stream id 0 378 | output[offset++] = 0x00; //stream id 0 379 | 380 | //flv VideoTagHeader 381 | output[offset++] = 0x17; //key frame, AVC 382 | output[offset++] = 0x01; //avc NALU unit 383 | output[offset++] = 0x00; //composit time ?????????? 384 | output[offset++] = 0x00; // composit time 385 | output[offset++] = 0x00; //composit time 386 | 387 | output[offset++] = (uint8_t)(nal_len >> 24); //nal length 388 | output[offset++] = (uint8_t)(nal_len >> 16); //nal length 389 | output[offset++] = (uint8_t)(nal_len >> 8); //nal length 390 | output[offset++] = (uint8_t)(nal_len); //nal length 391 | memcpy(output + offset, nal, nal_len); 392 | 393 | //no need set pre_tag_size ,RTMP NO NEED 394 | offset += nal_len; 395 | uint32_t fff = body_len + FLV_TAG_HEAD_LEN; 396 | output[offset++] = (uint8_t)(fff >> 24); //data len 397 | output[offset++] = (uint8_t)(fff >> 16); //data len 398 | output[offset++] = (uint8_t)(fff >> 8); //data len 399 | output[offset++] = (uint8_t)(fff); //data len 400 | write(flv_file, output, output_len); 401 | //RTMP Send out 402 | free(output); 403 | continue; 404 | } 405 | 406 | if (nal[0] == 0x61) 407 | { 408 | ts += 170; 409 | body_len = nal_len + 5 + 4; //flv VideoTagHeader + NALU length 410 | output_len = body_len + FLV_TAG_HEAD_LEN + FLV_PRE_TAG_LEN; 411 | output = malloc(output_len); 412 | // flv tag header 413 | output[offset++] = 0x09; //tagtype video 414 | output[offset++] = (uint8_t)(body_len >> 16); //data len 415 | output[offset++] = (uint8_t)(body_len >> 8); //data len 416 | output[offset++] = (uint8_t)(body_len); //data len 417 | output[offset++] = (uint8_t)(ts >> 16); //time stamp 418 | output[offset++] = (uint8_t)(ts >> 8); //time stamp 419 | output[offset++] = (uint8_t)(ts); //time stamp 420 | output[offset++] = (uint8_t)(ts >> 24); //time stamp 421 | output[offset++] = 0x00; //stream id 0 422 | output[offset++] = 0x00; //stream id 0 423 | output[offset++] = 0x00; //stream id 0 424 | 425 | //flv VideoTagHeader 426 | output[offset++] = 0x27; //key frame, AVC 427 | output[offset++] = 0x01; //avc NALU unit 428 | output[offset++] = 0x00; //composit time ?????????? 429 | output[offset++] = 0x00; // composit time 430 | output[offset++] = 0x00; //composit time 431 | 432 | output[offset++] = (uint8_t)(nal_len >> 24); //nal length 433 | output[offset++] = (uint8_t)(nal_len >> 16); //nal length 434 | output[offset++] = (uint8_t)(nal_len >> 8); //nal length 435 | output[offset++] = (uint8_t)(nal_len); //nal length 436 | memcpy(output + offset, nal, nal_len); 437 | 438 | //no need set pre_tag_size ,RTMP NO NEED 439 | offset += nal_len; 440 | uint32_t fff = body_len + FLV_TAG_HEAD_LEN; 441 | output[offset++] = (uint8_t)(fff >> 24); //data len 442 | output[offset++] = (uint8_t)(fff >> 16); //data len 443 | output[offset++] = (uint8_t)(fff >> 8); //data len 444 | output[offset++] = (uint8_t)(fff); //data len 445 | write(flv_file, output, output_len); 446 | 447 | //RTMP Send out 448 | free(output); 449 | continue; 450 | } 451 | 452 | } 453 | #endif 454 | 455 | 456 | } 457 | -------------------------------------------------------------------------------- /xiecc_rtmp.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "rtmp.h" 6 | #include "log.h" 7 | #include "xiecc_rtmp.h" 8 | 9 | #define AAC_ADTS_HEADER_SIZE 7 10 | #define FLV_TAG_HEAD_LEN 11 11 | #define FLV_PRE_TAG_LEN 4 12 | 13 | typedef struct { 14 | uint8_t audio_object_type; 15 | uint8_t sample_frequency_index; 16 | uint8_t channel_configuration; 17 | }AudioSpecificConfig; 18 | 19 | typedef struct 20 | { 21 | RTMP *rtmp; 22 | AudioSpecificConfig config; 23 | uint32_t audio_config_ok; 24 | uint32_t video_config_ok; 25 | uint32_t flag; 26 | }RTMP_XIECC; 27 | 28 | 29 | static AudioSpecificConfig gen_config(uint8_t *frame) 30 | { 31 | AudioSpecificConfig config = {0, 0, 0}; 32 | 33 | if (frame == NULL) { 34 | return config; 35 | } 36 | config.audio_object_type = (frame[2] & 0xc0) >> 6; 37 | config.sample_frequency_index = (frame[2] & 0x3c) >> 2; 38 | config.channel_configuration = (frame[3] & 0xc0) >> 6; 39 | return config; 40 | } 41 | 42 | static uint8_t gen_audio_tag_header(AudioSpecificConfig config) 43 | { 44 | uint8_t soundType = config.channel_configuration - 1; //0 mono, 1 stero 45 | uint8_t soundRate = 0; 46 | uint8_t val = 0; 47 | 48 | 49 | switch (config.sample_frequency_index) { 50 | case 10: { //11.025k 51 | soundRate = 1; 52 | break; 53 | } 54 | case 7: { //22k 55 | soundRate = 2; 56 | break; 57 | } 58 | case 4: { //44k 59 | soundRate = 3; 60 | break; 61 | } 62 | default: 63 | { 64 | return val; 65 | } 66 | } 67 | val = 0xA0 | (soundRate << 2) | 0x02 | soundType; 68 | return val; 69 | } 70 | static uint8_t *get_adts(uint32_t *len, uint8_t **offset, uint8_t *start, uint32_t total) 71 | { 72 | uint8_t *p = *offset; 73 | uint32_t frame_len_1; 74 | uint32_t frame_len_2; 75 | uint32_t frame_len_3; 76 | uint32_t frame_length; 77 | 78 | if (total < AAC_ADTS_HEADER_SIZE) { 79 | return NULL; 80 | } 81 | if ((p - start) >= total) { 82 | return NULL; 83 | } 84 | 85 | if (p[0] != 0xff) { 86 | return NULL; 87 | } 88 | if ((p[1] & 0xf0) != 0xf0) { 89 | return NULL; 90 | } 91 | frame_len_1 = p[3] & 0x03; 92 | frame_len_2 = p[4]; 93 | frame_len_3 = (p[5] & 0xe0) >> 5; 94 | frame_length = (frame_len_1 << 11) | (frame_len_2 << 3) | frame_len_3; 95 | *offset = p + frame_length; 96 | *len = frame_length; 97 | return p; 98 | } 99 | 100 | 101 | 102 | // @brief alloc function 103 | // @param [in] url : RTMP URL, rtmp://127.0.0.1/live/xxx 104 | // @return : rtmp_sender handler 105 | void *rtmp_sender_alloc(const char *url) //return handle 106 | { 107 | RTMP_XIECC *rtmp_xiecc; 108 | RTMP *rtmp; 109 | 110 | if (url == NULL) { 111 | return NULL; 112 | } 113 | RTMP_LogSetLevel(RTMP_LOGINFO); 114 | rtmp = RTMP_Alloc(); 115 | RTMP_Init(rtmp); 116 | rtmp->Link.timeout = 10; //10seconds 117 | rtmp->Link.lFlags |= RTMP_LF_LIVE; 118 | 119 | if (!RTMP_SetupURL(rtmp, (char *)url)) { 120 | RTMP_Log(RTMP_LOGWARNING, "Couldn't set the specified url (%s)!", url); 121 | RTMP_Free(rtmp); 122 | return NULL; 123 | } 124 | 125 | RTMP_EnableWrite(rtmp); 126 | rtmp_xiecc = calloc(1, sizeof(RTMP_XIECC)); 127 | rtmp_xiecc->rtmp = rtmp; 128 | return (void *)rtmp_xiecc; 129 | } 130 | 131 | // @brief start publish 132 | // @param [in] rtmp_sender handler 133 | // @param [in] flag stream falg 134 | // @param [in] ts_us timestamp in us 135 | // @return : 0: OK; others: FAILED 136 | static const AVal av_onMetaData = AVC("onMetaData"); 137 | static const AVal av_duration = AVC("duration"); 138 | static const AVal av_width = AVC("width"); 139 | static const AVal av_height = AVC("height"); 140 | static const AVal av_videocodecid = AVC("videocodecid"); 141 | static const AVal av_avcprofile = AVC("avcprofile"); 142 | static const AVal av_avclevel = AVC("avclevel"); 143 | static const AVal av_videoframerate = AVC("videoframerate"); 144 | static const AVal av_audiocodecid = AVC("audiocodecid"); 145 | static const AVal av_audiosamplerate = AVC("audiosamplerate"); 146 | static const AVal av_audiochannels = AVC("audiochannels"); 147 | static const AVal av_avc1 = AVC("avc1"); 148 | static const AVal av_mp4a = AVC("mp4a"); 149 | static const AVal av_onPrivateData = AVC("onPrivateData"); 150 | static const AVal av_record = AVC("record"); 151 | 152 | int rtmp_sender_set_stream_property(void *handle, uint32_t flag, const char *ext){ 153 | 154 | RTMP_XIECC *rtmp_xiecc = (RTMP_XIECC *)handle; 155 | if (rtmp_xiecc == NULL) { 156 | return 1; 157 | } 158 | rtmp_xiecc->flag = flag; 159 | if (flag == RTMP_STREAM_PROPERTY_PUBLIC) 160 | return rtmp_sender_stop_record(handle); 161 | else if (flag == RTMP_STREAM_PROPERTY_ALARM) 162 | return rtmp_sender_start_record(handle); 163 | else 164 | return rtmp_sender_start_record(handle); 165 | } 166 | 167 | int rtmp_sender_start_publish(void *handle, uint32_t flag, int64_t ts_us) 168 | { 169 | RTMP_XIECC *rtmp_xiecc = (RTMP_XIECC *)handle; 170 | RTMP *rtmp; 171 | int val = 0; 172 | uint32_t body_len; 173 | uint32_t offset = 0; 174 | uint32_t output_len; 175 | char buffer[48]; 176 | char *output = buffer; 177 | char *outend = buffer + sizeof(buffer); 178 | char send_buffer[512]; 179 | 180 | if (rtmp_xiecc == NULL) { 181 | return 1; 182 | } 183 | rtmp_xiecc->flag = flag; 184 | rtmp = rtmp_xiecc->rtmp; 185 | if (!RTMP_Connect(rtmp, NULL) || !RTMP_ConnectStream(rtmp, 0)) { 186 | return 1; 187 | } 188 | output = AMF_EncodeString(output, outend, &av_onMetaData); 189 | *output++ = AMF_ECMA_ARRAY; 190 | output = AMF_EncodeInt32(output, outend, 1); 191 | output = AMF_EncodeNamedNumber(output, outend, &av_duration, 0.0); 192 | body_len = output - buffer; 193 | output_len = body_len + FLV_TAG_HEAD_LEN + FLV_PRE_TAG_LEN; 194 | send_buffer[offset++] = 0x12; //tagtype scripte 195 | send_buffer[offset++] = (uint8_t)(body_len >> 16); //data len 196 | send_buffer[offset++] = (uint8_t)(body_len >> 8); //data len 197 | send_buffer[offset++] = (uint8_t)(body_len); //data len 198 | send_buffer[offset++] = (uint8_t)(ts_us >> 16); //time stamp 199 | send_buffer[offset++] = (uint8_t)(ts_us >> 8); //time stamp 200 | send_buffer[offset++] = (uint8_t)(ts_us); //time stamp 201 | send_buffer[offset++] = (uint8_t)(ts_us >> 24); //time stamp 202 | send_buffer[offset++] = 0x00; //stream id 0 203 | send_buffer[offset++] = 0x00; //stream id 0 204 | send_buffer[offset++] = 0x00; //stream id 0 205 | 206 | memcpy(send_buffer + offset, buffer, body_len); //H264 sequence parameter set 207 | //no need to set pre_tag_size 208 | /* 209 | offset += body_len; 210 | uint32_t fff = body_len + FLV_TAG_HEAD_LEN; 211 | output[offset++] = (uint8_t)(fff >> 24); //data len 212 | output[offset++] = (uint8_t)(fff >> 16); //data len 213 | output[offset++] = (uint8_t)(fff >> 8); //data len 214 | output[offset++] = (uint8_t)(fff); //data len 215 | */ 216 | val = RTMP_Write(rtmp, send_buffer, output_len); 217 | 218 | if (flag != RTMP_STREAM_PROPERTY_PUBLIC) { 219 | rtmp_sender_start_record(handle); 220 | } 221 | 222 | return val; 223 | } 224 | 225 | // @brief stop publish 226 | // @param [in] rtmp_sender handler 227 | // @return : 0: OK; others: FAILED 228 | int rtmp_sender_stop_publish(void *handle) 229 | { 230 | RTMP_XIECC *rtmp_xiecc = (RTMP_XIECC *)handle; 231 | RTMP *rtmp ; 232 | 233 | if (rtmp_xiecc == NULL) { 234 | return 1; 235 | } 236 | 237 | if (rtmp_xiecc->flag != RTMP_STREAM_PROPERTY_PUBLIC) { 238 | rtmp_sender_stop_record(handle); 239 | } 240 | rtmp = rtmp_xiecc->rtmp; 241 | RTMP_Close(rtmp); 242 | return 0; 243 | } 244 | 245 | //@brief start record current stream 246 | int rtmp_sender_start_record(void *handle) 247 | { 248 | RTMP_XIECC *rtmp_xiecc = (RTMP_XIECC *)handle; 249 | RTMP *rtmp; 250 | uint32_t body_len; 251 | uint32_t offset = 0; 252 | uint32_t output_len; 253 | char buffer[48]; 254 | char *output = buffer; 255 | char *outend = buffer + sizeof(buffer); 256 | char send_buffer[256]; 257 | int val = 0; 258 | 259 | if (rtmp_xiecc == NULL) { 260 | return -1; 261 | } 262 | rtmp = rtmp_xiecc->rtmp; 263 | output = AMF_EncodeString(output, outend, &av_onPrivateData); 264 | *output++ = AMF_ECMA_ARRAY; 265 | output = AMF_EncodeInt32(output, outend, 1); 266 | output = AMF_EncodeNamedNumber(output, outend, &av_record, 1); 267 | body_len = output - buffer; 268 | output_len = body_len + FLV_TAG_HEAD_LEN + FLV_PRE_TAG_LEN; 269 | send_buffer[offset++] = 0x12; //tagtype scripte 270 | send_buffer[offset++] = (uint8_t)(body_len >> 16); //data len 271 | send_buffer[offset++] = (uint8_t)(body_len >> 8); //data len 272 | send_buffer[offset++] = (uint8_t)(body_len); //data len 273 | send_buffer[offset++] = 0; //time stamp 274 | send_buffer[offset++] = 0; //time stamp 275 | send_buffer[offset++] = 0; //time stamp 276 | send_buffer[offset++] = 0; //time stamp 277 | send_buffer[offset++] = 0x00; //stream id 0 278 | send_buffer[offset++] = 0x00; //stream id 0 279 | send_buffer[offset++] = 0x00; //stream id 0 280 | 281 | memcpy(send_buffer + offset, buffer, body_len); 282 | val = RTMP_Write(rtmp, send_buffer, output_len); 283 | return val; 284 | } 285 | 286 | int rtmp_sender_stop_record(void *handle) 287 | { 288 | RTMP_XIECC *rtmp_xiecc = (RTMP_XIECC *)handle; 289 | RTMP *rtmp; 290 | int val = 0; 291 | uint32_t body_len; 292 | uint32_t offset = 0; 293 | uint32_t output_len; 294 | char buffer[48]; 295 | char *output = buffer; 296 | char *outend = buffer + sizeof(buffer); 297 | char send_buffer[256]; 298 | 299 | if (rtmp_xiecc == NULL) { 300 | return 1; 301 | } 302 | rtmp = rtmp_xiecc->rtmp; 303 | output = AMF_EncodeString(output, outend, &av_onPrivateData); 304 | *output++ = AMF_ECMA_ARRAY; 305 | output = AMF_EncodeInt32(output, outend, 1); 306 | output = AMF_EncodeNamedNumber(output, outend, &av_record, 0); 307 | body_len = output - buffer; 308 | output_len = body_len + FLV_TAG_HEAD_LEN + FLV_PRE_TAG_LEN; 309 | send_buffer[offset++] = 0x12; //tagtype scripte 310 | send_buffer[offset++] = (uint8_t)(body_len >> 16); //data len 311 | send_buffer[offset++] = (uint8_t)(body_len >> 8); //data len 312 | send_buffer[offset++] = (uint8_t)(body_len); //data len 313 | send_buffer[offset++] = 0; //time stamp 314 | send_buffer[offset++] = 0; //time stamp 315 | send_buffer[offset++] = 0; //time stamp 316 | send_buffer[offset++] = 0; //time stamp 317 | send_buffer[offset++] = 0x00; //stream id 0 318 | send_buffer[offset++] = 0x00; //stream id 0 319 | send_buffer[offset++] = 0x00; //stream id 0 320 | 321 | memcpy(send_buffer + offset, buffer, body_len); 322 | val = RTMP_Write(rtmp, send_buffer, output_len); 323 | return val; 324 | } 325 | 326 | 327 | // @brief send audio frame 328 | // @param [in] rtmp_sender handler 329 | // @param [in] data : AACAUDIODATA 330 | // @param [in] size : AACAUDIODATA size 331 | // @param [in] dts_us : decode timestamp of frame 332 | // @param [in] abs_ts : indicate whether you'd like to use absolute time stamp 333 | int rtmp_sender_write_audio_frame(void *handle, 334 | uint8_t *data, 335 | int size, 336 | uint64_t dts_us, 337 | uint32_t abs_ts) 338 | { 339 | RTMP_XIECC *rtmp_xiecc = (RTMP_XIECC *)handle; 340 | RTMP *rtmp ; 341 | int val = 0; 342 | uint32_t audio_ts = (uint32_t)dts_us; 343 | uint8_t * audio_buf = data; 344 | uint32_t audio_total = size; 345 | uint8_t *audio_buf_offset = audio_buf; 346 | uint8_t *audio_frame; 347 | uint32_t adts_len; 348 | uint32_t offset; 349 | uint32_t body_len; 350 | uint32_t output_len; 351 | char *output ; 352 | 353 | if ((data == NULL) || (rtmp_xiecc == NULL)) { 354 | return 1; 355 | } 356 | rtmp = rtmp_xiecc->rtmp; 357 | while (1) { 358 | //Audio OUTPUT 359 | offset = 0; 360 | audio_frame = get_adts(&adts_len, &audio_buf_offset, audio_buf, audio_total); 361 | if (audio_frame == NULL) break; 362 | if (rtmp_xiecc->audio_config_ok == 0) { 363 | rtmp_xiecc->config = gen_config(audio_frame); 364 | body_len = 2 + 2; //AudioTagHeader + AudioSpecificConfig 365 | output_len = body_len + FLV_TAG_HEAD_LEN + FLV_PRE_TAG_LEN; 366 | output = malloc(output_len); 367 | // flv tag header 368 | output[offset++] = 0x08; //tagtype video 369 | output[offset++] = (uint8_t)(body_len >> 16); //data len 370 | output[offset++] = (uint8_t)(body_len >> 8); //data len 371 | output[offset++] = (uint8_t)(body_len); //data len 372 | output[offset++] = (uint8_t)(audio_ts >> 16); //time stamp 373 | output[offset++] = (uint8_t)(audio_ts >> 8); //time stamp 374 | output[offset++] = (uint8_t)(audio_ts); //time stamp 375 | output[offset++] = (uint8_t)(audio_ts >> 24); //time stamp 376 | output[offset++] = abs_ts; //stream id 0 377 | output[offset++] = 0x00; //stream id 0 378 | output[offset++] = 0x00; //stream id 0 379 | 380 | //flv AudioTagHeader 381 | output[offset++] = gen_audio_tag_header(rtmp_xiecc->config); // sound format aac 382 | output[offset++] = 0x00; //aac sequence header 383 | 384 | //flv VideoTagBody --AudioSpecificConfig 385 | uint8_t audio_object_type = rtmp_xiecc->config.audio_object_type + 1; 386 | output[offset++] = (audio_object_type << 3)|(rtmp_xiecc->config.sample_frequency_index >> 1); 387 | output[offset++] = ((rtmp_xiecc->config.sample_frequency_index & 0x01) << 7) \ 388 | | (rtmp_xiecc->config.channel_configuration << 3) ; 389 | //no need to set pre_tag_size 390 | /* 391 | uint32_t fff = body_len + FLV_TAG_HEAD_LEN; 392 | output[offset++] = (uint8_t)(fff >> 24); //data len 393 | output[offset++] = (uint8_t)(fff >> 16); //data len 394 | output[offset++] = (uint8_t)(fff >> 8); //data len 395 | output[offset++] = (uint8_t)(fff); //data len 396 | */ 397 | val = RTMP_Write(rtmp, output, output_len); 398 | free(output); 399 | rtmp_xiecc->audio_config_ok = 1; 400 | }else 401 | { 402 | body_len = 2 + adts_len - AAC_ADTS_HEADER_SIZE; // remove adts header + AudioTagHeader 403 | output_len = body_len + FLV_TAG_HEAD_LEN + FLV_PRE_TAG_LEN; 404 | output = malloc(output_len); 405 | // flv tag header 406 | output[offset++] = 0x08; //tagtype video 407 | output[offset++] = (uint8_t)(body_len >> 16); //data len 408 | output[offset++] = (uint8_t)(body_len >> 8); //data len 409 | output[offset++] = (uint8_t)(body_len); //data len 410 | output[offset++] = (uint8_t)(audio_ts >> 16); //time stamp 411 | output[offset++] = (uint8_t)(audio_ts >> 8); //time stamp 412 | output[offset++] = (uint8_t)(audio_ts); //time stamp 413 | output[offset++] = (uint8_t)(audio_ts >> 24); //time stamp 414 | output[offset++] = abs_ts; //stream id 0 415 | output[offset++] = 0x00; //stream id 0 416 | output[offset++] = 0x00; //stream id 0 417 | 418 | //flv AudioTagHeader 419 | output[offset++] = gen_audio_tag_header(rtmp_xiecc->config); // sound format aac 420 | output[offset++] = 0x01; //aac raw data 421 | 422 | //flv VideoTagBody --raw aac data 423 | memcpy(output + offset, audio_frame + AAC_ADTS_HEADER_SIZE,\ 424 | (adts_len - AAC_ADTS_HEADER_SIZE)); //H264 sequence parameter set 425 | /* 426 | //previous tag size 427 | uint32_t fff = body_len + FLV_TAG_HEAD_LEN; 428 | offset += (adts_len - AAC_ADTS_HEADER_SIZE); 429 | output[offset++] = (uint8_t)(fff >> 24); //data len 430 | output[offset++] = (uint8_t)(fff >> 16); //data len 431 | output[offset++] = (uint8_t)(fff >> 8); //data len 432 | output[offset++] = (uint8_t)(fff); //data len 433 | */ 434 | val = RTMP_Write(rtmp, output, output_len); 435 | free(output); 436 | } 437 | } //end while 1 438 | return (val > 0) ? 0: -1; 439 | } 440 | 441 | static uint32_t find_start_code(uint8_t *buf, uint32_t zeros_in_startcode) 442 | { 443 | uint32_t info; 444 | uint32_t i; 445 | 446 | info = 1; 447 | if ((info = (buf[zeros_in_startcode] != 1)? 0: 1) == 0) 448 | return 0; 449 | 450 | for (i = 0; i < zeros_in_startcode; i++) 451 | if (buf[i] != 0) 452 | { 453 | info = 0; 454 | break; 455 | }; 456 | 457 | return info; 458 | } 459 | 460 | static uint8_t * get_nal(uint32_t *len, uint8_t **offset, uint8_t *start, uint32_t total) 461 | { 462 | uint32_t info; 463 | uint8_t *q ; 464 | uint8_t *p = *offset; 465 | *len = 0; 466 | 467 | if ((p - start) >= total) 468 | return NULL; 469 | 470 | while(1) { 471 | info = find_start_code(p, 3); 472 | if (info == 1) 473 | break; 474 | p++; 475 | if ((p - start) >= total) 476 | return NULL; 477 | } 478 | q = p + 4; 479 | p = q; 480 | while(1) { 481 | info = find_start_code(p, 3); 482 | if (info == 1) 483 | break; 484 | p++; 485 | if ((p - start) >= total) 486 | //return NULL; 487 | break; 488 | } 489 | 490 | *len = (p - q); 491 | *offset = p; 492 | return q; 493 | } 494 | 495 | // @brief send video frame, now only H264 supported 496 | // @param [in] rtmp_sender handler 497 | // @param [in] data : video data, (Full frames are required) 498 | // @param [in] size : video data size 499 | // @param [in] dts_us : decode timestamp of frame 500 | // @param [in] key : key frame indicate, [0: non key] [1: key] 501 | // @param [in] abs_ts : indicate whether you'd like to use absolute time stamp 502 | int rtmp_sender_write_video_frame(void *handle, 503 | uint8_t *data, 504 | int size, 505 | uint64_t dts_us, 506 | int key, 507 | uint32_t abs_ts) 508 | { 509 | uint8_t * buf; 510 | uint8_t * buf_offset; 511 | int val = 0; 512 | int total; 513 | uint32_t ts; 514 | uint32_t nal_len; 515 | uint32_t nal_len_n; 516 | uint8_t *nal; 517 | uint8_t *nal_n; 518 | char *output ; 519 | uint32_t offset = 0; 520 | uint32_t body_len; 521 | uint32_t output_len; 522 | RTMP_XIECC *rtmp_xiecc; 523 | RTMP *rtmp; 524 | 525 | 526 | buf = data; 527 | buf_offset = data; 528 | total = size; 529 | ts = (uint32_t)dts_us; 530 | rtmp_xiecc = (RTMP_XIECC *)handle; 531 | if ((data == NULL) || (rtmp_xiecc == NULL)) { 532 | return 1; 533 | } 534 | rtmp = rtmp_xiecc->rtmp; 535 | 536 | while (1) { 537 | //ts = RTMP_GetTime() - start_time; 538 | offset = 0; 539 | nal = get_nal(&nal_len, &buf_offset, buf, total); 540 | if (nal == NULL) break; 541 | if (nal[0] == 0x67) { 542 | if (rtmp_xiecc->video_config_ok > 0) { 543 | //only send video seq set once; 544 | continue; 545 | } 546 | nal_n = get_nal(&nal_len_n, &buf_offset, buf, total); //get pps 547 | if (nal_n == NULL) { 548 | RTMP_Log(RTMP_LOGERROR, "No Nal after SPS\n"); 549 | break; 550 | } 551 | body_len = nal_len + nal_len_n + 16; 552 | output_len = body_len + FLV_TAG_HEAD_LEN + FLV_PRE_TAG_LEN; 553 | output = malloc(output_len); 554 | // flv tag header 555 | output[offset++] = 0x09; //tagtype video 556 | output[offset++] = (uint8_t)(body_len >> 16); //data len 557 | output[offset++] = (uint8_t)(body_len >> 8); //data len 558 | output[offset++] = (uint8_t)(body_len); //data len 559 | output[offset++] = (uint8_t)(ts >> 16); //time stamp 560 | output[offset++] = (uint8_t)(ts >> 8); //time stamp 561 | output[offset++] = (uint8_t)(ts); //time stamp 562 | output[offset++] = (uint8_t)(ts >> 24); //time stamp 563 | output[offset++] = abs_ts; //stream id 0 564 | output[offset++] = 0x00; //stream id 0 565 | output[offset++] = 0x00; //stream id 0 566 | 567 | //flv VideoTagHeader 568 | output[offset++] = 0x17; //key frame, AVC 569 | output[offset++] = 0x00; //avc sequence header 570 | output[offset++] = 0x00; //composit time ?????????? 571 | output[offset++] = 0x00; // composit time 572 | output[offset++] = 0x00; //composit time 573 | 574 | //flv VideoTagBody --AVCDecoderCOnfigurationRecord 575 | output[offset++] = 0x01; //configurationversion 576 | output[offset++] = nal[1]; //avcprofileindication 577 | output[offset++] = nal[2]; //profilecompatibilty 578 | output[offset++] = nal[3]; //avclevelindication 579 | output[offset++] = 0xff; //reserved + lengthsizeminusone 580 | output[offset++] = 0xe1; //numofsequenceset 581 | output[offset++] = (uint8_t)(nal_len >> 8); //sequence parameter set length high 8 bits 582 | output[offset++] = (uint8_t)(nal_len); //sequence parameter set length low 8 bits 583 | memcpy(output + offset, nal, nal_len); //H264 sequence parameter set 584 | offset += nal_len; 585 | output[offset++] = 0x01; //numofpictureset 586 | output[offset++] = (uint8_t)(nal_len_n >> 8); //picture parameter set length high 8 bits 587 | output[offset++] = (uint8_t)(nal_len_n); //picture parameter set length low 8 bits 588 | memcpy(output + offset, nal_n, nal_len_n); //H264 picture parameter set 589 | 590 | //no need set pre_tag_size ,RTMP NO NEED 591 | // flv test 592 | /* 593 | offset += nal_len_n; 594 | uint32_t fff = body_len + FLV_TAG_HEAD_LEN; 595 | output[offset++] = (uint8_t)(fff >> 24); //data len 596 | output[offset++] = (uint8_t)(fff >> 16); //data len 597 | output[offset++] = (uint8_t)(fff >> 8); //data len 598 | output[offset++] = (uint8_t)(fff); //data len 599 | */ 600 | val = RTMP_Write(rtmp, output, output_len); 601 | //RTMP Send out 602 | free(output); 603 | rtmp_xiecc->video_config_ok = 1; 604 | continue; 605 | } 606 | 607 | if (nal[0] == 0x65) 608 | { 609 | body_len = nal_len + 5 + 4; //flv VideoTagHeader + NALU length 610 | output_len = body_len + FLV_TAG_HEAD_LEN + FLV_PRE_TAG_LEN; 611 | output = malloc(output_len); 612 | // flv tag header 613 | output[offset++] = 0x09; //tagtype video 614 | output[offset++] = (uint8_t)(body_len >> 16); //data len 615 | output[offset++] = (uint8_t)(body_len >> 8); //data len 616 | output[offset++] = (uint8_t)(body_len); //data len 617 | output[offset++] = (uint8_t)(ts >> 16); //time stamp 618 | output[offset++] = (uint8_t)(ts >> 8); //time stamp 619 | output[offset++] = (uint8_t)(ts); //time stamp 620 | output[offset++] = (uint8_t)(ts >> 24); //time stamp 621 | output[offset++] = abs_ts; //stream id 0 622 | output[offset++] = 0x00; //stream id 0 623 | output[offset++] = 0x00; //stream id 0 624 | 625 | //flv VideoTagHeader 626 | output[offset++] = 0x17; //key frame, AVC 627 | output[offset++] = 0x01; //avc NALU unit 628 | output[offset++] = 0x00; //composit time ?????????? 629 | output[offset++] = 0x00; // composit time 630 | output[offset++] = 0x00; //composit time 631 | 632 | output[offset++] = (uint8_t)(nal_len >> 24); //nal length 633 | output[offset++] = (uint8_t)(nal_len >> 16); //nal length 634 | output[offset++] = (uint8_t)(nal_len >> 8); //nal length 635 | output[offset++] = (uint8_t)(nal_len); //nal length 636 | memcpy(output + offset, nal, nal_len); 637 | 638 | //no need set pre_tag_size ,RTMP NO NEED 639 | /* 640 | offset += nal_len; 641 | uint32_t fff = body_len + FLV_TAG_HEAD_LEN; 642 | output[offset++] = (uint8_t)(fff >> 24); //data len 643 | output[offset++] = (uint8_t)(fff >> 16); //data len 644 | output[offset++] = (uint8_t)(fff >> 8); //data len 645 | output[offset++] = (uint8_t)(fff); //data len 646 | */ 647 | val = RTMP_Write(rtmp, output, output_len); 648 | //RTMP Send out 649 | free(output); 650 | continue; 651 | } 652 | 653 | if ((nal[0] & 0x1f) == 0x01) 654 | { 655 | body_len = nal_len + 5 + 4; //flv VideoTagHeader + NALU length 656 | output_len = body_len + FLV_TAG_HEAD_LEN + FLV_PRE_TAG_LEN; 657 | output = malloc(output_len); 658 | // flv tag header 659 | output[offset++] = 0x09; //tagtype video 660 | output[offset++] = (uint8_t)(body_len >> 16); //data len 661 | output[offset++] = (uint8_t)(body_len >> 8); //data len 662 | output[offset++] = (uint8_t)(body_len); //data len 663 | output[offset++] = (uint8_t)(ts >> 16); //time stamp 664 | output[offset++] = (uint8_t)(ts >> 8); //time stamp 665 | output[offset++] = (uint8_t)(ts); //time stamp 666 | output[offset++] = (uint8_t)(ts >> 24); //time stamp 667 | output[offset++] = abs_ts; //stream id 0 668 | output[offset++] = 0x00; //stream id 0 669 | output[offset++] = 0x00; //stream id 0 670 | 671 | //flv VideoTagHeader 672 | output[offset++] = 0x27; //not key frame, AVC 673 | output[offset++] = 0x01; //avc NALU unit 674 | output[offset++] = 0x00; //composit time ?????????? 675 | output[offset++] = 0x00; // composit time 676 | output[offset++] = 0x00; //composit time 677 | 678 | output[offset++] = (uint8_t)(nal_len >> 24); //nal length 679 | output[offset++] = (uint8_t)(nal_len >> 16); //nal length 680 | output[offset++] = (uint8_t)(nal_len >> 8); //nal length 681 | output[offset++] = (uint8_t)(nal_len); //nal length 682 | memcpy(output + offset, nal, nal_len); 683 | 684 | //no need set pre_tag_size ,RTMP NO NEED 685 | /* 686 | offset += nal_len; 687 | uint32_t fff = body_len + FLV_TAG_HEAD_LEN; 688 | output[offset++] = (uint8_t)(fff >> 24); //data len 689 | output[offset++] = (uint8_t)(fff >> 16); //data len 690 | output[offset++] = (uint8_t)(fff >> 8); //data len 691 | output[offset++] = (uint8_t)(fff); //data len 692 | */ 693 | val = RTMP_Write(rtmp, output, output_len); 694 | 695 | //RTMP Send out 696 | free(output); 697 | continue; 698 | } 699 | } 700 | return (val > 0) ? 0: -1; 701 | } 702 | 703 | // @brief free rtmp_sender handler 704 | // @param [in] rtmp_sender handler 705 | void rtmp_sender_free(void *handle) 706 | { 707 | RTMP_XIECC *rtmp_xiecc; 708 | RTMP *rtmp; 709 | 710 | if (handle == NULL) { 711 | return; 712 | } 713 | 714 | rtmp_xiecc = (RTMP_XIECC *)handle; 715 | rtmp = rtmp_xiecc->rtmp; 716 | if (rtmp != NULL) { 717 | RTMP_Free(rtmp); 718 | } 719 | free(rtmp_xiecc); 720 | } 721 | --------------------------------------------------------------------------------