Frage

Ich dekodiere Videos über libavcodec mit dem folgenden Code:

//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);
}

Der Code funktioniert ordnungsgemäß, es ist jedoch erforderlich, jeden Frame in das erforderliche Format zu konvertieren.Ist es möglich, das Pixelformat für die Decodierung festzulegen, um das richtige Format ohne sws_scale zu erhalten?

Vielen Dank für Ihre Antworten.

War es hilfreich?

Lösung

ffmpegvon AVCodec instanzen (statische Decoder- "Factory" -Objekte) definieren jeweils ein Array von Pixelformaten, die sie unterstützen, abgeschlossen mit dem Wert -1.

Der AVCodecContext (Decoder-Instanz) Objekte haben einen Callback-Funktionszeiger namens get_format:es ist ein Funktionszeiger in dieser Struktur.

Diese Callback-Funktion wird irgendwann in der Codec-Initialisierung mit dem aufgerufen AVCodec das Array der unterstützten Formate des Factory-Objekts, und der Rückruf soll eines der Formate aus diesem Array auswählen (ähnlich wie "Wähle eine Karte, eine beliebige Karte") und diesen Wert zurückgeben.Die Standardimplementierung dieses get_format callback ist eine Funktion namens avcodec_default_get_format.(Dies ist installiert avcodec_get_context_defaults2).Diese Standardfunktion implementiert die Logik "Format auswählen" ganz einfach:es wählt das erste Element des Arrays aus, das kein reines Hardware-Beschleunigungs-Pixelformat ist.

Wenn Sie möchten, dass der Codec mit einem anderen Pixelformat arbeitet, können Sie Ihr eigenes installieren get_format callback in das Kontextobjekt.Der Rückruf muss jedoch einen der Werte im Array zurückgeben (wie bei der Auswahl aus einem Menü).Es kann keinen beliebigen Wert zurückgeben.Der Codec unterstützt nur die Formate, die er im Array angibt.

Gehen Sie durch die Reihe der verfügbaren Formate und wählen Sie das beste aus.Wenn du Glück hast, ist es genau das, was du eigentlich willst und das sws_scale die Funktion muss keine Pixelformatkonvertierung durchführen.(Wenn Sie zusätzlich nicht anfordern, das Bild zu skalieren oder zuzuschneiden, sollte sws_scale erkennen, dass die Konvertierung ein Noop ist.)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top