zoukankan      html  css  js  c++  java
  • (转)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 }

     

  • 相关阅读:
    转转帖.NET.GC 浅谈.net托管程序中的资源释放问题 (转帖)
    [转]来谈谈从专业到更专业
    [转]ASP.NET中多国语言的实现
    [转]内向的人如何建立人际网络
    SQL 入门 (代码)
    SQL 查询 (代码)
    关于学生信息处理小代码
    SQL 函数 (代码)
    SQL 链接 (代码)
    SQL 数据表的相关操作
  • 原文地址:https://www.cnblogs.com/billcoco/p/2553939.html
Copyright © 2011-2022 走看看