2012-03-11 27 views
9

decodifico video tramite libavcodec, utilizzando il seguente codice:Come impostare il formato del pixel di decodifica in 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); 
} 

Il codice funziona correttamente, ma è necessario convertire ogni fotogramma nel formato richiesto. E 'possibile impostare il formato pixel per la decodifica per ottenere il formato corretto senza sws_scale?

Mille grazie per le vostre risposte.

risposta

14

ffmpeg Le istanze di AVCodec (oggetti "factory" del decodificatore statico) definiscono ciascuna una matrice di formati di pixel supportati, terminata dal valore -1.

Gli oggetti AVCodecContext (istanza decoder) hanno un puntatore di funzione di richiamata chiamato get_format: è un puntatore di funzione in quella struttura.

Questa funzione di callback viene richiamata, ad un certo punto nell'inizializzazione del codec, con la matrice dell'oggetto AVCodec di formati supportati e il callback deve scegliere uno dei formati da tale array (un po 'come "scegli una scheda"). , qualsiasi carta ") e restituire quel valore. L'implementazione predefinita di questo callback get_format è una funzione denominata avcodec_default_get_format. (Questo è installato avcodec_get_context_defaults2). Questa funzione di default implementa la logica del "pick a format" in modo abbastanza semplice: sceglie il primo elemento dell'array che non è un formato pixel solo per l'hardware.

Se si desidera che il codec funzioni con un diverso formato di pixel, è possibile installare la propria callback get_format nell'oggetto di contesto. Tuttavia, il callback deve restituire uno dei valori dell'array (come la scelta da un menu). Non può restituire un valore arbitrario. Il codec supporterà solo i formati che specifica nell'array.

Cammina la gamma di formati disponibili e scegli la migliore. Se sei fortunato, è esattamente quello che vuoi e la funzione sws_scale non dovrà convertire i formati in pixel. (Se, inoltre, non si richiede di ridimensionare o ritagliare l'immagine, sws_scale dovrebbe riconoscere che la conversione è un noop.)

+1

P.S. il posto in cui inserire il callback di override sarebbe prima di 'avcodec_open'. Intendiamoci, è da un po 'che non guardo queste cose. – Kaz

+0

Grazie, Kaz! – kochedykov