2012-03-11 26 views
9

I dekodowania wideo poprzez libavcodec, stosując następujący kod:Jak ustawić format pikseli dekodowania w 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); 
} 

Kod działa poprawnie, ale konieczne jest, aby przekształcić każdą klatkę do wymaganego formatu. Czy można ustawić format dekodowania piksela, aby uzyskać prawidłowy format bez opcji sws_scale?

Wielkie dzięki za twoje odpowiedzi.

Odpowiedz

14

ffmpeg 'instancje AVCodec (dekodery statyczne "obiekty fabryczne") definiują tablicę formatów pikseli, które obsługują, zakończone wartością -1.

Obiekty AVCodecContext (instancja dekodera) mają wskaźnik funkcji zwrotnej o nazwie get_format: jest to wskaźnik funkcji w tej strukturze.

Ta funkcja wywołania zwrotnego jest wywoływana w pewnym momencie podczas inicjowania kodeków z tablicą obiektów fabrycznych AVCodec obsługiwanych formatów, a wywołanie zwrotne ma wybrać jeden z formatów z tej tablicy (rodzaj "wybierz kartę" , dowolna karta ") i zwróć tę wartość. Domyślna implementacja tego wywołania zwrotnego get_format jest funkcją o nazwie avcodec_default_get_format. (To jest zainstalowane avcodec_get_context_defaults2). Ta domyślna funkcja implementuje logikę "wybierz format" w prosty sposób: wybiera pierwszy element tablicy, który nie jest formatem piksela opartym wyłącznie na sprzęcie.

Jeśli chcesz, aby kodek działał z innym formatem pikseli, możesz zainstalować własne wywołanie zwrotne get_format w obiekcie kontekstowym. Jednak wywołanie zwrotne musi zwrócić jedną z wartości w tablicy (np. Wybierając z menu). Nie może zwrócić arbitralnej wartości. Kodek obsługuje tylko formaty określone w tablicy.

Spaceruj po tablicy dostępnych formatów i wybierz najlepszy z nich. Jeśli masz szczęście, jest to dokładnie to, czego potrzebujesz, a funkcja sws_scale nie będzie musiała wykonywać konwersji w formacie pikseli. (Jeśli dodatkowo nie chcesz przeskalować ani przyciąć obrazu, sws_scale powinien rozpoznać, że konwersja jest odłożona.)

+1

P.S. miejsce do wstawienia w nadrzędnym wywołaniu zwrotnym byłoby przed 'avcodec_open'. Pamiętaj, minęło trochę czasu, odkąd spojrzałem na te rzeczy. – Kaz

+0

Dziękuję, Kaz! – kochedykov