どのようにlibavcodecでデコードピクセル形式を設定するには?
-
11-12-2019 - |
質問
次のコードを使用して、libavcodecを介してビデオをデコードします:
//Open input file
if(avformat_open_input(&ctx, filename, NULL, NULL)!=0)
return FALSE; // Couldn't open file
if(avformat_find_stream_info(ctx, NULL)<0)
return FALSE; // Couldn't find stream information
videoStream = -1;
//find video stream
for(i=0; i<ctx->nb_streams; i++)
{
if((ctx->streams[i])->codec->codec_type==AVMEDIA_TYPE_VIDEO)
{
videoStream=i;
break;
}
}
if (videoStream == -1)
return FALSE; // Didn't find a video stream
video_codec_ctx=ctx->streams[videoStream]->codec;
//find decoder
video_codec=avcodec_find_decoder(video_codec_ctx->codec_id);
if(video_codec==NULL)
return FALSE; // Codec not found
if(avcodec_open(video_codec_ctx, video_codec)<0)
return -1; // Could not open codec
video_frame=avcodec_alloc_frame();
scaled_frame=avcodec_alloc_frame();
static struct SwsContext *img_convert_ctx;
if(img_convert_ctx == NULL)
{
int w = video_codec_ctx->width;
int h = video_codec_ctx->height;
img_convert_ctx = sws_getContext(w, h,
video_codec_ctx->pix_fmt,
w, h, dst_pix_fmt, SWS_BICUBIC,
NULL, NULL, NULL);
if(img_convert_ctx == NULL) {
fprintf(stderr, "Cannot initialize the conversion context!\n");
return FALSE;
}
}
while(b_play)
{
if (av_read_frame(ctx, &packet) < 0)
{
break;
}
if(packet.stream_index==videoStream) {
// Decode video frame
avcodec_decode_video2(video_codec_ctx, video_frame, &frameFinished,
&packet);
// Did we get a video frame?
if(frameFinished)
{
if (video_codec_ctx->pix_fmt != dst_pix_fmt)
{
if (video_codec_ctx->pix_fmt != dst_pix_fmt)
sws_scale(img_convert_ctx, video_frame->data,
video_frame->linesize, 0,
video_codec_ctx->height,
scaled_frame->data, scaled_frame->linesize);
}
}
}
av_free_packet(&packet);
}
コードは正しく機能しますが、各フレームを必要な形式に変換する必要があります。Sws_scaleなしで正しい形式を取得するためにデコード用のピクセル形式を設定することは可能ですか?
あなたの答えに感謝します。
解決
ffmpeg
'sの AVCodec
インスタンス(静的デコーダ"ファクトリ"オブジェクト)はそれぞれ、サポートするピクセル形式の配列を定義し、値-1で終了します。
ザ- AVCodecContext
(decoderインスタンス)オブジェクトには、コールバック関数ポインタが呼び出されます get_format
:それはその構造体の関数ポインタです。
このコールバック関数は、コーデックの初期化のある時点で、次のように呼び出されます AVCodec
ファクトリオブジェクトのサポートされている形式の配列であり、コールバックはその配列から形式の1つを選択し(「カード、任意のカードを選択」のような)、その値を返すことになっています。これのデフォルトの実装は、次のとおりです。 get_format
コールバックは呼び出される関数です avcodec_default_get_format
.(これはインストールされています avcodec_get_context_defaults2
).このデフォルト関数は、"pick a format"ロジックを非常に簡単に実装します:これは、ハードウェアアクセルオンリーのピクセル形式ではない配列の最初の要素を選択します。
コーデックを別のピクセル形式で動作させたい場合は、独自のものをインストールすることができます get_format
コンテキストオブジェクトへのコールバック。ただし、コールバックは配列内の値の1つを返す必要があります(メニューから選択するなど)。任意の値を返すことはできません。コーデックは、配列内で指定された形式のみをサポートします。
利用可能なフォーマットの配列を歩き、最高のものを選んでください。あなたが運が良ければ、それはあなたが実際に望む正確なものです sws_scale
関数は、ピクセル形式の変換を行う必要はありません。(さらに、画像の拡大縮小またはトリミングを要求しない場合、sws_scaleは変換がnoopであることを認識する必要があります。)