FFmpegã¯ã¹ã¤ã«1-frame-in-1-frame-outãããªã
ã©ããFFmpegã1-frame-in-1-frame-outã«ç¸ããããã®ãããªããã¨ã®誤解があったã®ã§ãµã³ãã«ã交ãã¦èª¤è§£ã解ãã¦ã¿ãããµã³ãã«ã¯FFmpeg APIで、さまざまな動画を操る - 前編 (1/5):CodeZine(コードジン)ããæåããã
#include <libavcodec/avformat.h> #include <libavcodec/avdevice.h> /* FFmpegã®åæå */ avcodec_register_all(); avdevice_register_all(); av_register_all();
ã¾ãããã¯ãç´æã
/* ãã¡ã¤ã«ã®ããããèªã¿ããã©ã¼ããããå¾ã */ AVFormatContext *formatCtx; ret = av_open_input_file(&formatCtx, filename, NULL, 0, NULL); if(ret != 0) error("can't open input file."); /* ãã¡ã¤ã«ã®ä¸èº«ããã¹ããªã¼ã æ å ±ãå¾ã */ ret = av_find_stream_info(formatCtx); if(ret < 0) error("can't find stream info.");
ããã§ã¡ãã£ã¢ãã©ã¼ããããå¤å¥ãã¦ãã®ä¸ã«ããåå¥ã®ã¹ããªã¼ã ã®æ å ±ãå¾ããå¾ãããæ å ±ã¯ãã¹ã¦AVFormatContextã«ä¿åããããformatCtx->streamsã«AVStreamã¨ãã¦åã¹ããªã¼ã ã®æ å ±ãããã®ã§ãããè¦ã¦æ åã¹ããªã¼ã ãæ¢ãã
/* ãããªã¹ããªã¼ã ãæ¢ã */ int streamIndex = -1; for(i = 0; i < formatCtx->nb_streams; i++){ if(formatCtx->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO){ /* ãããªã¹ããªã¼ã ãçºè¦ */ streamIndex = i; break; } } if(streamIndex < 0) error("can't find video stream."); AVCodecContext *codecCtx = formatCtx->streams[streamIndex]->codec;
ã¹ããªã¼ã æ å ±ã®ä¸ã«ã³ã¼ããã¯ã®æ å ±ãAVCodecContextã¨ãã¦ããã®ã§å¾ã®ããã«åãåºãã¦ããã
/* codecãæ¢ã */ AVCodec *codec = avcodec_find_decoder(codecCtx->codec_id); if(codec == NULL) error("can't find codec(decoder)."); /* codecãéã */ ret = avcodec_open(codecCtx, codec); if(ret != 0) error("can't open codec(decoder).");
ãã³ã¼ããæ¢ãã¦é©åãªãã©ã¡ã¼ã¿(AVCodecContextã«ãã§ã«è¨å®æ¸ã¿)ã§åæåããã
/* ãã¡ã¤ã«ãããã±ãããèªã¿è¾¼ã */ AVPacket packet; while(av_read_frame(formatCtx, &packet) >= 0){ /* åç»ã¹ããªã¼ã 以å¤ã¯é£ã°ã */ if(packet.stream_index != streamIndex) goto LAST; /* ãã¼ã¿ãåãåããã¬ã¼ã ã®ä½æ */ AVFrame *frame = avcodec_alloc_frame(); if(frame == NULL) error("can't allocate a frame to store data."); /* ãã±ãããããã¬ã¼ã ã復å·ãã */ avcodec_decode_video(codecCtx, frame, &isFinish, packet.data, packet.size); /* 復å·ãã¾ã ã®å ´åã¯æ¬¡ã®ãã±ããã¾ã§å¦çãé£ã°ã */ if(! isFinish) goto LAST; /* frameã«é¢ããå¦ç ex.)ç»é¢ã«è¡¨ç¤ºãã */ LAST: /* ãã±ãããè§£æ¾ */ av_free_packet(&packet); } /* ã³ã¼ããã¯ãéãã */ avcodec_close(codecCtx); /* ãã¡ã¤ã«ãéãã */ av_close_input_file(formatCtx); /* 確ä¿ããã¡ã¢ãªã解æ¾ãã */ av_freep(&frame);
ããããã³ã¼ãã®ã¡ã¤ã³ã«ã¼ãã«ãªããã¹ããªã¼ã ãããã±ãã(http://cekirdek.pardus.org.tr/~ismail/ffmpeg-docs/structAVPacket.html)ã¨ããã¹ããªã¼ã ãå°åãã«ã1ãã¬ã¼ã åã®ãã¼ã¿ã«ãããã®ãåãåã£ã¦avcodec_decode_video()ã§ãã³ã¼ããã¦ãã¬ã¼ã (AVFrame)ã«ããããã®éãisFinishã0ã«ãªãå¯è½æ§ããããã¨ã«æ³¨æãisFinishã常ã«0ã§ãªããªã1-frame-in-1-frame-outã¨ãããã0ã®å ´åãããããã®ã§1-frame-in-1-frame-outã¨ããããã§ã¯ãªãã
ã¾ãAVFrameã«ã¯ä»¥ä¸ã®ãããªãã£ã¼ã«ããããã
int64_t pts; int coded_picture_number; int display_picture_number;
ptsã¯ã¾ãã¾PTS*1ã§ãããcoded_picture_numberã¨display_picture_numberãéãå¤ãã¨ããã¨ã¯å¥ã«åé¡ãªãã
ãã³ã¼ãã«é¢ãã¦ã ãã§ã¯ãªãã¨ã³ã³ã¼ãã«ã¤ãã¦ãæ¸ãã¦ããã¨ãã¬ã¼ã ãavcodec_encode_video()ã«æ¸¡ãã¦ãããã¹ããªã¼ã ãå¾ã¦ããããã±ããã«ã¤ããã¨ããä½æ¥ã«ãªãããã®ã¨ãã§ã常ã«ãããã¹ããªã¼ã ãå¾ãããã¨ã¯éããªãããã¬ã¼ã ã渡ãã¦ããµã¤ãº0ã®ãããã¹ããªã¼ã ãè¿ã£ã¦ãããã¨ãããã
/* ãã¬ã¼ã ã符ååãã */ int out_size = avcodec_encode_video ( codecCtx, buf, buf_size, frame ); /* 符å·åãã¾ã ã®å ´åã¯ã次ã®ãã¬ã¼ã 㸠*/ if (out_size == 0){ continue; } else if (out_size < 0){ error("can't encode frame."); } AVPacket packet; av_init_packet(&packet); packet.stream_index= stream->index; packet.data= buf; packet.size= out_size; /* codecã®time baseã«ããptsãstreamã®time baseã«ãããã®ã«ä¿®æ£ */ packet.pts= av_rescale_q( codecCtx->coded_frame->pts, codecCtx->time_base, stream->time_base ); if(codecCtx->coded_frame->key_frame) packet.flags |= PKT_FLAG_KEY;
ãã®ããã«FFmpegããã³ãã®ä¸ã®ã©ã¤ãã©ãªlibavcodecãlibavformatã¯1-frame-in-1-frame-outã«ç¸ããã¦ãã¯ããªãã
*1:Presentation Time Stamp