Como definir decodificar o formato de pixel em libavcodec?
-
11-12-2019 - |
Pergunta
Eu decodificação de vídeo através de libavcodec, usando o seguinte código:
//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);
}
O código funciona corretamente, mas é necessário converter cada quadro para o formato necessário.É possível definir o formato de pixel para a decodificação para obter o formato correto, sem sws_scale?
Muito obrigado por suas respostas.
Solução
ffmpeg
's AVCodec
instâncias (estático decodificador de "fábrica" de objetos) cada definir uma matriz de formatos de pixel que eles suportam, finalizado pelo valor -1.
O AVCodecContext
(decodificador de instância) objetos têm uma função de retorno de chamada ponteiro chamado get_format
:é um ponteiro de função em que se estrutura.
Esta função de retorno de chamada é chamada, em algum momento da inicialização do codec, com o AVCodec
fábrica do objeto de matriz de formatos suportados, e o retorno de chamada é suposto escolher um dos formatos a partir dessa matriz (uma espécie de "escolha uma carta, qualquer carta") e retornar o valor.A implementação padrão desse get_format
de retorno de chamada é uma função chamada avcodec_default_get_format
.(Esta é instalado avcodec_get_context_defaults2
).Esta função padrão implementa a "escolha um formato de" lógica bastante simples:ele escolhe o primeiro elemento da matriz, o que não é um hardware de aceleração-somente o formato de pixel.
Se você deseja que o codec para trabalhar com um diferente formato de pixel, o que você pode fazer é instalar o seu próprio get_format
chamada de retorno para o objeto de contexto.No entanto, o retorno de chamada deve retornar a um dos valores em matriz (como a escolha de um menu).Ele não pode retornar um valor arbitrário.O codec irá apenas suporte a formatos que especifica na matriz.
Andar a variedade de formatos disponíveis e escolha a melhor.Se você tiver sorte, ele é exatamente o que você realmente quer e o sws_scale
função não tem a fazer pixel de conversão de formato.(Se, além disso, você não solicitação de escala ou cortar a imagem, sws_scale deve reconhecer que a conversão é um noop.)