您的位置:首页 > 编程语言 > PHP开发

FFmpeg SDK使用实例output_example的分析之二

2014-04-19 22:15 519 查看
四、主函数代码

001 int main(int argc, char **argv)

002 {

003 const char *filename;

004 AVOutputFormat *fmt;

005 AVFormatContext *oc;

006 AVStream *audio_st, *video_st;

007 double audio_pts, video_pts;

008 int i;

/* initialize libavcodec, and register all codecs and formats */

009 av_register_all();

010 if (argc != 2) {

011 printf("usage: %s output_file\n"

"API example program to output a media file with libavformat.\n"

"The output format is automatically guessed according to the file extension.\n"

"Raw images can also be output by using '%%d' in the filename\n"

"\n", argv[0]);

012 exit(1);

}

013 filename = argv[1];

/* auto detect the output format from the name. default is mpeg. */

014 fmt = guess_format(NULL, filename, NULL);

015 if (!fmt) {

016 printf("Could not deduce output format from file extension: using MPEG.\n");

017 fmt = guess_format("mpeg", NULL, NULL);

018 }

019 if (!fmt) {

fprintf(stderr, "Could not find suitable output format\n");

exit(1);

}

/* allocate the output media context */

020 oc = avformat_alloc_context();

021 if (!oc) {

022 fprintf(stderr, "Memory error\n");

023 exit(1);

024 }

025 oc->oformat = fmt;

026 snprintf(oc->filename, sizeof(oc->filename), "%s", filename);

/* add the audio and video streams using the default format codecs

and initialize the codecs */

027 video_st = NULL;

028 audio_st = NULL;

029 if (fmt->video_codec != CODEC_ID_NONE) {

030 video_st = add_video_stream(oc, fmt->video_codec);

031 }

032 if (fmt->audio_codec != CODEC_ID_NONE) {

033 audio_st = add_audio_stream(oc, fmt->audio_codec);

034 }

/* set the output parameters (must be done even if no parameters). */

035 if (av_set_parameters(oc, NULL) < 0) {

036 fprintf(stderr, "Invalid output format parameters\n");

037 exit(1);

038 }

039 dump_format(oc, 0, filename, 1);

/* now that all the parameters are set, we can open the audio and

video codecs and allocate the necessary encode buffers */

040 if (video_st)

041 open_video(oc, video_st);

042 if (audio_st)

043 open_audio(oc, audio_st);

/* open the output file, if needed */

044 if (!(fmt->flags & AVFMT_NOFILE)) {

045 if (url_fopen(&oc->pb, filename, URL_WRONLY) < 0) {

046 fprintf(stderr, "Could not open '%s'\n", filename);

047 exit(1);

048 }

049 }

/* write the stream header, if any */

050 av_write_header(oc);

051 for(;;) {

/* compute current audio and video time */

052 if (audio_st)

053 audio_pts = (double)audio_st->pts.val * audio_st->time_base.num / audio_st->time_base.den;

054 else

055 audio_pts = 0.0;

056 if (video_st)

057 video_pts = (double)video_st->pts.val * video_st->time_base.num / video_st->time_base.den;

058 else

059 video_pts = 0.0;

060 if ((!audio_st || audio_pts >= STREAM_DURATION) &&

061 (!video_st || video_pts >= STREAM_DURATION))

062 break;

/* write interleaved audio and video frames */

063 if (!video_st || (video_st && audio_st && audio_pts < video_pts)) {

064 write_audio_frame(oc, audio_st);

065 } else {

066 write_video_frame(oc, video_st);

067 }

068 }

/* write the trailer, if any. the trailer must be written

* before you close the CodecContexts open when you wrote the

* header; otherwise write_trailer may try to use memory that

* was freed on av_codec_close() */

069 av_write_trailer(oc);

/* close each codec */

070 if (video_st)

071 close_video(oc, video_st);

072 if (audio_st)

073 close_audio(oc, audio_st);

/* free the streams */

074 for(i = 0; i < oc->nb_streams; i++) {

075 av_freep(&oc->streams[i]->codec);

076 av_freep(&oc->streams[i]);

077 }

078 if (!(fmt->flags & AVFMT_NOFILE)) {

079 /* close the output file */

080 url_fclose(oc->pb);

081 }

082 /* free the stream */

083 av_free(oc);

084 return 0;

085 }



五、主函数流程分析

1. 该例子讲了如何输出一个libavformat库所支持格式的媒体文件。

(1)av_register_all(),初始化libavcodec库,并注册所有的编解码器和格式。

(2)guess_format(),根据文件名来获取输出文件格式,默认为mpeg。

(3)av_alloc_format_context()分配输出媒体内容。

  ov->oformat = fmt;

  snprintf( oc->filename, sizeof(oc->filename), “%s”, filename );

(4)add_video_stream()使用默认格式的编解码器来增加一个视频流,并初始化编解码器。

  (4.1)av_new_stream()增加一个新的流到一个媒体文件。

  (4.2)初始化编解码器:

    c = st->codec;

    c->codec_id = codec_id;

    c->codec_type = CODEC_TYPE_VIDEO;

    c->bit_rate = 400000;

    c->width = 352;

    c->height = 288;

    c->time_base.den = STREAM_FRAME_RATE; //每秒25副图像

    c->time_base.num = 1;

    c->gop_size = 12;

    c->pix_fmt = STREAM_PIX_FMT; //默认格式为PIX_FMT_YUV420P

    …… ……

(5)av_set_parameters()设置输出参数,即使没有参数,该函数也必须被调用。

(6)dump_format()输出格式信息,用于调试。

(7)open_video()打开视频编解码器并分配必要的编码缓存。

  (7.1)avcodec_find_encoder()寻找c->codec_id指定的视频编码器。

  (7.2)avcodec_open()打开编码器。

  (7.3)分配视频输出缓存:

    video_outbuf_size = 200000;

    video_outbuf = av_malloc( video_outbuf_size );

  (7.4)picture = alloc_picture()分配原始图像。

    (7.4.1)avcodec_alloc_frame()分配一个AVFrame并设置默认值。

    (7.4.2)size = avpicture_get_size()计算对于给定的图片格式以及宽和高,所需占用多少内存。

    (7.4.3)picture_buf = av_malloc( size )分配所需内存。

    (7.4.4)avpicture_fill()填充AVPicture的域。

  (7.5)可选。如果输出格式不是YUV420P,那么临时的YUV420P格式的图像也是需要的,

由此再转换为我们所需的格式,因此需要为临时的YUV420P图像分配缓存:

   tmp_picture = alloc_picture()

说明:tmp_picture,picture,video_outbuf。

如果输出格式为YUV420P,则直接通过avcodec_encode_video()函数,

将picture缓存中的原始图像编码保存到video_outbuf缓存中;

如果输出格式不是YUV420P,则需要先通过sws_scale()函数,将YUV420P格式转换为目标格式,

此时tmp_picture缓存存放的是YUV420P格式的图像,而picture缓存为转换为目标格式后保存的图像,

进而再将picture缓存中的图像编码保存到video_outbuf缓存中。

(8)url_fopen()打开输出文件,如果需要的话。

(9)av_write_header()写流动头部。

(10)LOOP循环{

    计算当前视频时间video_pts

    是否超时退出循环?

    write_video_frame()视频编码

  }

  (10.1)write_video_frame()

    如果图片不是YUV420P,则需要用sws_scale()函数先进行格式转换。

    若需要原始图像:

      av_init_packet()初始化一个包的选项域。

      av_write_frame()向输出媒体文件写一个包,该包会包含一个视频帧。

    若需要编码图像:

      avcodec_encode_video()编码一视频帧。

      av_init_packet()

      av_write_frame()

(11)close_video()关闭每个编解码器。

(12)av_write_trailer()写流的尾部。

(13)释放资源

  av_freep()释放AVFormatContext下的AVStream->AVCodecContext和AVStream:

    for( i = 0; i < oc->nb_streams; i++ ){

      av_freep( &oc->streams[i]->codec );

      av_freep( &oc->streams[i] );

    }

  url_fclose()关闭输出文件。

  av_free()释放AVFormatContext。

2. 流程图



原文《FFMpeg的output_example.c例子分析 》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: