(转)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 }

 

 

posted on 2012-06-18 19:21  billcoco  阅读(3721)  评论(3编辑  收藏  举报

导航