C++, verwenden Sie ffmpeg, um die Videotranscodierung zu extrahieren und zu speichern

//Einige große Abschnitte von Bemerkungen sind maschinelle Übersetzungen, kennen Sie nur die allgemeine Bedeutung.

//C++, verwenden Sie ffmpeg, um die Videotranscodierung zu extrahieren und als separate Datei zu speichern. Dieses Beispiel ist ein Überprüfungsprogramm. Nur wenn Sie dieses Programm verstehen, können Sie ffmpge verwenden, um einen Player oder so etwas zu erstellen.

#include <QCoreApplication>
#include <iostream>
using namespace std;
extern "C"{     #include <libavcodec/avcodec.h>     #include <libavformat/avformat.h> }



int main(int argc, char *argv[])
{     QCoreApplication a(argc, argv);

    //const char* url {"a.mkv"};
    const char* url {"b.mp4"};
    const char* out {"out.yuv"};
    AVFormatContext *fmt_ctx {};
    int re = avformat_open_input(
                &fmt_ctx , //AVFormatContext
                url,
                0, // 0 bedeutet automatische Auswahl des Decapsulators
                0 //Parametereinstellungen wie rtsp delay time
                );
    if(re<0)
    {         cout<<"avformat_open_input err"<<endl;         exit (- 1);     }


    av_dump_format(fmt_ctx, 0, url, 0);//Dateiinformationen drucken

    re = avformat_find_stream_info(fmt_ctx, 0);//Stream-Informationen abrufen
    if(re<0)
    {         cout<<"avformat_find_stream_info err"<<endl;         exit(-1);     }


    re=av_find_best_stream(fmt_ctx,AVMEDIA_TYPE_VIDEO,-1,-1,NULL,0);//Finde den "besten" Stream in der Datei. Der beste Stream wird basierend auf verschiedenen Heuristiken bestimmt, da er höchstwahrscheinlich das ist, was der Benutzer erwartet hat. Wenn der Decoder-Parameter nicht null ist, findet av_find_best_stream den Standard-Decoder für den Codec des Streams; Streams, für die kein Decoder gefunden werden kann, werden ignoriert.
    if(re<0)
    {         cout<<"av_find_best_stream err"<<endl;         exit(-1);     }


    int stream_index=re;
    AVStream *video_stream=fmt_ctx->streams[stream_index];
    const AVCodec *av_dec=avcodec_find_decoder(video_stream->codecpar->codec_id);//Finde einen registrierten Decoder mit passender Codec-ID.

    AVCodecContext *dec_ctx=avcodec_alloc_context3(av_dec);//Ordne einen AVCodecContext zu und setze seine Felder auf Standardwerte. Die resultierende Struktur sollte mit avcodec_free_context() freigegeben werden.

    re=avcodec_parameters_to_context(dec_ctx,video_stream->codecpar); //Fülle den Codec-Kontext gemäß den Werten der bereitgestellten Codec-Parameter. Im Codec werden alle zugewiesenen Felder, die ein entsprechendes Feld in „par“ haben, freigegeben und durch eine Kopie des entsprechenden Felds in par ersetzt. Felder, die kein entsprechendes Feld im Codec haben, werden nicht geändert.
    if(re<0)
    {         cout<<"avcodec_parameters_to_context err"<<endl;         exit(-1);     }


    re=avcodec_open2(dec_ctx,av_dec,nullptr);
    if(re<0)
    {         cout<<"avcodec_open2 err"<<endl;         Ausgang (-1);     }



    DATEI *output_video_file=fopen(out,"wb");
    if(!output_video_file)
    {         cout<<"fopen(out,wb) err"<<endl;         Ausgang (-1);     }


    av_dump_format(fmt_ctx,0,url,0); //Dateiinformationen drucken, die sich von den obigen unterscheiden
    video_stream=fmt_ctx->streams[stream_index];
    cout<<"video_stream="<<video_stream<<endl;


    AVPacket *pkt= av_packet_alloc();

    AVFrame *frame= av_frame_alloc();

    while(av_read_frame(fmt_ctx,pkt)>=0) //Gib den nächsten Frame des Streams zurück. Diese Funktion gibt zurück, was in der Datei gespeichert ist, und überprüft nicht, ob der Decoder einen gültigen Rahmen hat. Es teilt den in der Datei gespeicherten Inhalt in Frames auf und gibt für jeden Aufruf einen Frame zurück. Es lässt keine ungültigen Daten zwischen gültigen Frames aus, um dem Decoder die maximal mögliche Information zum Decodieren zu geben. Bei Erfolg wird das zurückgegebene Paket referenzgezählt (pkt->buf set) und ist unbegrenzt gültig. Wenn das Paket nicht mehr benötigt wird, muss es mit av_packet_unref() freigegeben werden. Bei Video enthält ein Paket nur einen Frame. Wenn für Audio jeder Rahmen eine bekannte feste Größe hat (wie PCM- oder ADPCM-Daten), enthält er eine ganzzahlige Rahmennummer. Wenn der Audioframe eine variable Größe hat (z. B. MPEG-Audio), dann enthält er einen Frame. pkt->pts, pkt->dts und pkt->duration werden im AVStream immer auf die richtigen Werte gesetzt. Time_base-Einheiten (schätzen Sie, ob das Format sie nicht bereitstellen kann). pkt->pts kann AV_NOPTS_VALUE sein, wenn das Videoformat B-Frames enthält, daher ist es besser, sich auf pkt->dts zu verlassen, wenn Sie die Nutzdaten nicht dekomprimieren.
    {         int re {0};         if(pkt->stream_index==stream_index)         {             re=avcodec_send_packet(dec_ctx,pkt);             if(re<0)             {                 cout<<"avcodec_send_packet err"<<endl;                 break;









            while(1)
            {                 re=avcodec_receive_frame(dec_ctx,frame);//Avcodec_send_packet可能需要多次avcodec_receive_frame                 if(re<0)                 {                     cout<<"avcodec_receive_frame err"<<endl;                     brechen;                 }                //write_frame_to_yuv(frame);                 uint8_t **pBuf=frame->data;                 int *pStride=frame->linesize;                 for(size_t i=0;i<3;i++)                 {                     int32_t width=(i==0?frame->width:frame->width/2);                     int32_t height=(i==0?frame->height:frame->height/2);













                    for(size_t j=0;j<height;j++)
                    {                         fwrite(pBuf[i],1,width,output_video_file);                         pBuf[i]+=pStride[i];                     }                 }                 cout<<"frame="<< frame<<endl;               //write_frame_to_yuv(frame); Oben ist die Dateischreibfunktion             }






        }

        av_packet_unref(pt);

    }

//
    Av_frame_free(&frame);
    av_packet_free(&pkt);
    avcodec_free_context(&dec_ctx);
    avformat_close_input(&fmt_ctx);
    if (output_video_file != nullptr) {         fclose(output_video_file);         output_video_file = nullptr;         cout<<"output_video_file close"<<endl;


    }

Ende:
    Rückgabe a.exec();

}
/*
 Die erzeugte out.yuv-Datei wird mit folgendem Befehl getestet: Achten Sie auf die Auflösung der Videodatei, unterschiedliche Auflösungen müssen angepasst werden, zB 1920x800, 640x320, etc. ffplay -f rawvideo -video_size 1920x800 out
. jav
*/
 

Acho que você gosta

Origin blog.csdn.net/wangz76/article/details/125584185
Recomendado
Clasificación