(转)FFMpeg写MP4文件例子分析 .
这段时间看了FFMpeg提供的例子muxing.c,我略微修改了下源代码,使其生成一个MP4文件,音频使用AAC编码,视频使用H.264编码。代码很简单,我就不做说明了,代码如下。
以后我们继续写如何将DirectShow中采集的音视频数据编码并生成MP4文件。
1 /* 5 seconds stream duration */ 2 #define STREAM_DURATION 5.0 3 #define STREAM_FRAME_RATE 25 /* 25 images/s */ 4 #define STREAM_NB_FRAMES ((int)(STREAM_DURATION * STREAM_FRAME_RATE)) 5 #define STREAM_PIX_FMT PIX_FMT_YUV420P /* default pix_fmt */ 6 7 static int sws_flags = SWS_BICUBIC; 8 9 /**************************************************************/ 10 /* audio output */ 11 12 static float t, tincr, tincr2; 13 static int16_t *samples; 14 static uint8_t *audio_outbuf; 15 static int audio_outbuf_size; 16 static int audio_input_frame_size; 17 18 /* 19 * add an audio output stream 20 */ 21 static AVStream *add_audio_stream(AVFormatContext *oc, enum CodecID codec_id) 22 { 23 AVCodecContext *c; 24 AVStream *st; 25 26 st = avformat_new_stream(oc, NULL); 27 if (!st) { 28 fprintf(stderr, "Could not alloc stream\n"); 29 exit(1); 30 } 31 st->id = 1; 32 33 c = st->codec; 34 c->codec_id = codec_id; 35 c->codec_type = AVMEDIA_TYPE_AUDIO; 36 37 /* put sample parameters */ 38 c->sample_fmt = AV_SAMPLE_FMT_S16; 39 c->bit_rate = 64000; 40 c->sample_rate = 44100; 41 c->channels = 2; 42 43 // some formats want stream headers to be separate 44 if (oc->oformat->flags & AVFMT_GLOBALHEADER) 45 c->flags |= CODEC_FLAG_GLOBAL_HEADER; 46 47 return st; 48 } 49 50 static void open_audio(AVFormatContext *oc, AVStream *st) 51 { 52 AVCodecContext *c; 53 AVCodec *codec; 54 55 c = st->codec; 56 57 /* find the audio encoder */ 58 codec = avcodec_find_encoder(c->codec_id); 59 if (!codec) { 60 fprintf(stderr, "codec not found\n"); 61 exit(1); 62 } 63 64 /* open it */ 65 if (avcodec_open(c, codec) < 0) { 66 fprintf(stderr, "could not open codec\n"); 67 exit(1); 68 } 69 70 /* init signal generator */ 71 t = 0; 72 tincr = 2 * M_PI * 110.0 / c->sample_rate; 73 /* increment frequency by 110 Hz per second */ 74 tincr2 = 2 * M_PI * 110.0 / c->sample_rate / c->sample_rate; 75 76 audio_outbuf_size = 10000; 77 audio_outbuf = (uint8_t *)av_malloc(audio_outbuf_size); 78 79 /* ugly hack for PCM codecs (will be removed ASAP with new PCM 80 support to compute the input frame size in samples */ 81 if (c->frame_size <= 1) { 82 audio_input_frame_size = audio_outbuf_size / c->channels; 83 switch(st->codec->codec_id) { 84 case CODEC_ID_PCM_S16LE: 85 case CODEC_ID_PCM_S16BE: 86 case CODEC_ID_PCM_U16LE: 87 case CODEC_ID_PCM_U16BE: 88 audio_input_frame_size >>= 1; 89 break; 90 default: 91 break; 92 } 93 } else { 94 audio_input_frame_size = c->frame_size; 95 } 96 samples = (int16_t *)av_malloc(audio_input_frame_size * 2 * c->channels); 97 } 98 99 /* prepare a 16 bit dummy audio frame of 'frame_size' samples and 100 'nb_channels' channels */ 101 static void get_audio_frame(int16_t *samples, int frame_size, int nb_channels) 102 { 103 int j, i, v; 104 int16_t *q; 105 106 q = samples; 107 for (j = 0; j < frame_size; j++) { 108 v = (int)(sin(t) * 10000); 109 for(i = 0; i < nb_channels; i++) 110 *q++ = v; 111 t += tincr; 112 tincr += tincr2; 113 } 114 } 115 116 static void write_audio_frame(AVFormatContext *oc, AVStream *st) 117 { 118 AVCodecContext *c; 119 AVPacket pkt; 120 av_init_packet(&pkt); 121 122 c = st->codec; 123 124 get_audio_frame(samples, audio_input_frame_size, c->channels); 125 126 pkt.size = avcodec_encode_audio(c, audio_outbuf, audio_outbuf_size, samples); 127 128 if (c->coded_frame && c->coded_frame->pts != AV_NOPTS_VALUE) 129 pkt.pts= av_rescale_q(c->coded_frame->pts, c->time_base, st->time_base); 130 pkt.flags |= AV_PKT_FLAG_KEY; 131 pkt.stream_index = st->index; 132 pkt.data = audio_outbuf; 133 134 /* write the compressed frame in the media file */ 135 if (av_interleaved_write_frame(oc, &pkt) != 0) { 136 fprintf(stderr, "Error while writing audio frame\n"); 137 exit(1); 138 } 139 } 140 141 static void close_audio(AVFormatContext *oc, AVStream *st) 142 { 143 avcodec_close(st->codec); 144 145 av_free(samples); 146 av_free(audio_outbuf); 147 } 148 149 /**************************************************************/ 150 /* video output */ 151 152 static AVFrame *picture, *tmp_picture; 153 static uint8_t *video_outbuf; 154 static int frame_count, video_outbuf_size; 155 156 /* add a video output stream */ 157 static AVStream *add_video_stream(AVFormatContext *oc, enum CodecID codec_id) 158 { 159 AVCodecContext *c; 160 AVStream *st; 161 AVCodec *codec; 162 163 st = avformat_new_stream(oc, NULL); 164 if (!st) { 165 fprintf(stderr, "Could not alloc stream\n"); 166 exit(1); 167 } 168 169 c = st->codec; 170 171 /* find the video encoder */ 172 codec = avcodec_find_encoder(codec_id); 173 if (!codec) { 174 fprintf(stderr, "codec not found\n"); 175 exit(1); 176 } 177 avcodec_get_context_defaults3(c, codec); 178 179 c->codec_id = codec_id; 180 181 /* put sample parameters */ 182 c->bit_rate = /*400000*/3000000; 183 /* resolution must be a multiple of two */ 184 c->width = /*352*/640; 185 c->height = /*288*/480; 186 /* time base: this is the fundamental unit of time (in seconds) in terms 187 of which frame timestamps are represented. for fixed-fps content, 188 timebase should be 1/framerate and timestamp increments should be 189 identically 1. */ 190 c->time_base.den = STREAM_FRAME_RATE; 191 c->time_base.num = 1; 192 c->gop_size = 12; /* emit one intra frame every twelve frames at most */ 193 c->pix_fmt = STREAM_PIX_FMT; 194 if (c->codec_id == CODEC_ID_MPEG2VIDEO) { 195 /* just for testing, we also add B frames */ 196 c->max_b_frames = 2; 197 } 198 if (c->codec_id == CODEC_ID_MPEG1VIDEO){ 199 /* Needed to avoid using macroblocks in which some coeffs overflow. 200 This does not happen with normal video, it just happens here as 201 the motion of the chroma plane does not match the luma plane. */ 202 c->mb_decision=2; 203 } 204 // some formats want stream headers to be separate 205 if (oc->oformat->flags & AVFMT_GLOBALHEADER) 206 c->flags |= CODEC_FLAG_GLOBAL_HEADER; 207 208 209 210 return st; 211 } 212 213 static AVFrame *alloc_picture(enum PixelFormat pix_fmt, int width, int height) 214 { 215 AVFrame *picture; 216 uint8_t *picture_buf; 217 int size; 218 219 picture = avcodec_alloc_frame(); 220 if (!picture) 221 return NULL; 222 size = avpicture_get_size(pix_fmt, width, height); 223 picture_buf = (uint8_t *)av_malloc(size); 224 if (!picture_buf) { 225 av_free(picture); 226 return NULL; 227 } 228 avpicture_fill((AVPicture *)picture, picture_buf, 229 pix_fmt, width, height); 230 return picture; 231 } 232 233 static void open_video(AVFormatContext *oc, AVStream *st) 234 { 235 AVCodec *codec; 236 AVCodecContext *c; 237 238 c = st->codec; 239 240 /* find the video encoder */ 241 codec = avcodec_find_encoder(c->codec_id); 242 if (!codec) { 243 fprintf(stderr, "codec not found\n"); 244 exit(1); 245 } 246 247 /* open the codec */ 248 if (avcodec_open(c, codec) < 0) { 249 fprintf(stderr, "could not open codec\n"); 250 exit(1); 251 } 252 253 video_outbuf = NULL; 254 if (!(oc->oformat->flags & AVFMT_RAWPICTURE)) { 255 /* allocate output buffer */ 256 /* XXX: API change will be done */ 257 /* buffers passed into lav* can be allocated any way you prefer, 258 as long as they're aligned enough for the architecture, and 259 they're freed appropriately (such as using av_free for buffers 260 allocated with av_malloc) */ 261 video_outbuf_size = 200000; 262 video_outbuf = (uint8_t *)av_malloc(video_outbuf_size); 263 } 264 265 /* allocate the encoded raw picture */ 266 picture = alloc_picture(c->pix_fmt, c->width, c->height); 267 if (!picture) { 268 fprintf(stderr, "Could not allocate picture\n"); 269 exit(1); 270 } 271 272 /* if the output format is not YUV420P, then a temporary YUV420P 273 picture is needed too. It is then converted to the required 274 output format */ 275 tmp_picture = NULL; 276 if (c->pix_fmt != PIX_FMT_YUV420P) { 277 tmp_picture = alloc_picture(PIX_FMT_YUV420P, c->width, c->height); 278 if (!tmp_picture) { 279 fprintf(stderr, "Could not allocate temporary picture\n"); 280 exit(1); 281 } 282 } 283 } 284 285 /* prepare a dummy image */ 286 static void fill_yuv_image(AVFrame *pict, int frame_index, int width, int height) 287 { 288 int x, y, i; 289 290 i = frame_index; 291 292 /* Y */ 293 for (y = 0; y < height; y++) { 294 for (x = 0; x < width; x++) { 295 pict->data[0][y * pict->linesize[0] + x] = x + y + i * 3; 296 } 297 } 298 299 /* Cb and Cr */ 300 for (y = 0; y < height/2; y++) { 301 for (x = 0; x < width/2; x++) { 302 pict->data[1][y * pict->linesize[1] + x] = 128 + y + i * 2; 303 pict->data[2][y * pict->linesize[2] + x] = 64 + x + i * 5; 304 } 305 } 306 } 307 308 static void write_video_frame(AVFormatContext *oc, AVStream *st) 309 { 310 int out_size, ret; 311 AVCodecContext *c; 312 static struct SwsContext *img_convert_ctx; 313 314 c = st->codec; 315 316 if (frame_count >= STREAM_NB_FRAMES) { 317 /* no more frame to compress. The codec has a latency of a few 318 frames if using B frames, so we get the last frames by 319 passing the same picture again */ 320 } else { 321 if (c->pix_fmt != PIX_FMT_YUV420P) { 322 /* as we only generate a YUV420P picture, we must convert it 323 to the codec pixel format if needed */ 324 if (img_convert_ctx == NULL) { 325 img_convert_ctx = sws_getContext(c->width, c->height, 326 PIX_FMT_YUV420P, 327 c->width, c->height, 328 c->pix_fmt, 329 sws_flags, NULL, NULL, NULL); 330 if (img_convert_ctx == NULL) { 331 fprintf(stderr, "Cannot initialize the conversion context\n"); 332 exit(1); 333 } 334 } 335 fill_yuv_image(tmp_picture, frame_count, c->width, c->height); 336 sws_scale(img_convert_ctx, tmp_picture->data, tmp_picture->linesize, 337 0, c->height, picture->data, picture->linesize); 338 } else { 339 fill_yuv_image(picture, frame_count, c->width, c->height); 340 } 341 } 342 343 344 if (oc->oformat->flags & AVFMT_RAWPICTURE) { 345 /* raw video case. The API will change slightly in the near 346 future for that. */ 347 AVPacket pkt; 348 av_init_packet(&pkt); 349 350 pkt.flags |= AV_PKT_FLAG_KEY; 351 pkt.stream_index = st->index; 352 pkt.data = (uint8_t *)picture; 353 pkt.size = sizeof(AVPicture); 354 355 ret = av_interleaved_write_frame(oc, &pkt); 356 } else { 357 /* encode the image */ 358 out_size = avcodec_encode_video(c, video_outbuf, video_outbuf_size, picture); 359 /* if zero size, it means the image was buffered */ 360 if (out_size > 0) { 361 AVPacket pkt; 362 av_init_packet(&pkt); 363 364 if (c->coded_frame->pts != AV_NOPTS_VALUE) 365 pkt.pts= av_rescale_q(c->coded_frame->pts, c->time_base, st->time_base); 366 if(c->coded_frame->key_frame) 367 pkt.flags |= AV_PKT_FLAG_KEY; 368 pkt.stream_index = st->index; 369 pkt.data = video_outbuf; 370 pkt.size = out_size; 371 372 // printf("pts %d \n", c->coded_frame->pts); 373 374 /* write the compressed frame in the media file */ 375 ret = av_interleaved_write_frame(oc, &pkt); 376 } else { 377 ret = 0; 378 } 379 } 380 if (ret != 0) { 381 fprintf(stderr, "Error while writing video frame\n"); 382 exit(1); 383 } 384 frame_count++; 385 } 386 387 static void close_video(AVFormatContext *oc, AVStream *st) 388 { 389 avcodec_close(st->codec); 390 av_free(picture->data[0]); 391 av_free(picture); 392 if (tmp_picture) { 393 av_free(tmp_picture->data[0]); 394 av_free(tmp_picture); 395 } 396 av_free(video_outbuf); 397 } 398 399 /**************************************************************/ 400 /* media file output */ 401 402 403 int main(int argc, char **argv) 404 { 405 const char *filename; 406 AVOutputFormat *fmt; 407 AVFormatContext *oc; 408 AVStream *audio_st, *video_st; 409 double audio_pts, video_pts; 410 int i; 411 412 /* initialize libavcodec, and register all codecs and formats */ 413 av_register_all(); 414 415 #if 0 416 if (argc != 2) { 417 printf("usage: %s output_file\n" 418 "API example program to output a media file with libavformat.\n" 419 "The output format is automatically guessed according to the file extension.\n" 420 "Raw images can also be output by using '%%d' in the filename\n" 421 "\n", argv[0]); 422 return 1; 423 } 424 425 filename = argv[1]; 426 #endif 427 428 //#define RTMP_STREAM 429 #ifdef RTMP_STREAM 430 filename = "rtmp://192.168.0.239/live/livestream"; 431 #else 432 filename = "1.mp4"; 433 #endif 434 435 /* allocate the output media context */ 436 avformat_alloc_output_context2(&oc, NULL, NULL, filename); 437 if (!oc) 438 { 439 printf("Could not deduce output format from file extension: using MPEG.\n"); 440 avformat_alloc_output_context2(&oc, NULL, /*"mpeg"*/"flv", filename); 441 } 442 443 if (!oc) 444 { 445 return 1; 446 } 447 448 // 强制指定 264 编码 449 oc->oformat->video_codec = CODEC_ID_H264; 450 oc->oformat->audio_codec = CODEC_ID_AAC; 451 452 fmt = oc->oformat; 453 454 /* add the audio and video streams using the default format codecs 455 and initialize the codecs */ 456 video_st = NULL; 457 audio_st = NULL; 458 if (fmt->video_codec != CODEC_ID_NONE) { 459 video_st = add_video_stream(oc, fmt->video_codec); 460 } 461 if (fmt->audio_codec != CODEC_ID_NONE) { 462 audio_st = add_audio_stream(oc, fmt->audio_codec); 463 } 464 465 av_dump_format(oc, 0, filename, 1); 466 467 /* now that all the parameters are set, we can open the audio and 468 video codecs and allocate the necessary encode buffers */ 469 if (video_st) 470 open_video(oc, video_st); 471 if (audio_st) 472 open_audio(oc, audio_st); 473 474 /* open the output file, if needed */ 475 if (!(fmt->flags & AVFMT_NOFILE)) { 476 if (avio_open(&oc->pb, filename, AVIO_FLAG_WRITE) < 0) { 477 fprintf(stderr, "Could not open '%s'\n", filename); 478 return 1; 479 } 480 } 481 482 /* write the stream header, if any */ 483 avformat_write_header(oc, NULL); 484 picture->pts = 0; 485 for(;;) 486 { 487 /* compute current audio and video time */ 488 if (audio_st) 489 audio_pts = (double)audio_st->pts.val * audio_st->time_base.num / audio_st->time_base.den; 490 else 491 audio_pts = 0.0; 492 493 if (video_st) 494 video_pts = (double)video_st->pts.val * video_st->time_base.num / video_st->time_base.den; 495 else 496 video_pts = 0.0; 497 498 if ((!audio_st || audio_pts >= STREAM_DURATION) && 499 (!video_st || video_pts >= STREAM_DURATION)) 500 break; 501 502 /* write interleaved audio and video frames */ 503 if (!video_st || (video_st && audio_st && audio_pts < video_pts)) { 504 write_audio_frame(oc, audio_st); 505 506 } else { 507 write_video_frame(oc, video_st); 508 509 picture->pts++; 510 } 511 } 512 513 /* write the trailer, if any. the trailer must be written 514 * before you close the CodecContexts open when you wrote the 515 * header; otherwise write_trailer may try to use memory that 516 * was freed on av_codec_close() */ 517 av_write_trailer(oc); 518 519 /* close each codec */ 520 if (video_st) 521 close_video(oc, video_st); 522 if (audio_st) 523 close_audio(oc, audio_st); 524 525 /* free the streams */ 526 for(i = 0; i < oc->nb_streams; i++) { 527 av_freep(&oc->streams[i]->codec); 528 av_freep(&oc->streams[i]); 529 } 530 531 if (!(fmt->flags & AVFMT_NOFILE)) { 532 /* close the output file */ 533 avio_close(oc->pb); 534 } 535 536 /* free the stream */ 537 av_free(oc); 538 539 return 0; 540 }