Come impostare il formato di Decode Pixel in LIBAVCODEC?
-
11-12-2019 - |
Domanda
I decodifica video via libavcodec, utilizzando il seguente codice:
//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);
}
.
Il codice funziona correttamente, ma è necessario convertire ciascun telaio nel formato richiesto. È possibile impostare il formato pixel per la decodifica per ottenere il formato corretto senza SWS_Scale?
Molte grazie per le tue risposte.
Soluzione
ffmpeg
's AVCodec
Gcode istanze (decodificatore statico "Factory" oggetti) Ogni definisce una serie di formati pixel che supportano, terminati dal valore -1.
Gli oggetti AVCodecContext
(Istanza decodificatore) hanno un puntatore della funzione di callback chiamato get_format
: è un puntatore funzione in quella struttura.
Questa funzione di callback viene chiamata, ad un certo punto nell'inizializzazione del codec, con l'array dell'oggetto dell'oggetto di fabbrica di AVCodec
dei formati supportati e il callback dovrebbe scegliere uno dei formati da tale array (tipo di simile "selezionare una carta, qualsiasi carta ") e restituire quel valore. L'implementazione predefinita di questa callback di get_format
è una funzione chiamata avcodec_default_get_format
. (Questo è installato avcodec_get_context_defaults2
). Questa funzione predefinita implementa la logica "Scegli un formato" nella logica semplicemente: sceglie il primo elemento dell'array che non è un formato di pixel ad accelerazione hardware.
Se si desidera che il codec funzioni con un diverso formato pixel, ciò che puoi fare è installare la propria callback get_format
nell'oggetto di contesto. Tuttavia, il callback deve restituire uno dei valori nell'array (come scegliere da un menu). Non può restituire un valore arbitrario. Il codec supporterà solo i formati che specifica nell'array.
Passa la matrice dei formati disponibili e scegli il migliore. Se sei fortunato, è esattamente quello che desideri e la funzione sws_scale
non dovrà fare la conversione del formato pixel. (Se, inoltre, non si richiede di scalare o ritagliare l'immagine, SWS_Scale dovrebbe riconoscere che la conversione è un noop.)