C++, use ffmpeg para extrair a transcodificação de vídeo e salvá-la

//Algumas grandes seções de comentários são traduções automáticas, apenas conheça o significado geral.

//C++, use ffmpeg para extrair a transcodificação de vídeo e salve-o como um arquivo separado. Este exemplo é um programa de verificação. Somente quando você entender este programa, poderá usar o ffmpge para criar um player ou algo assim.

#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 significa seleção automática do decapsulator
                0 //Configurações de parâmetros, como rtsp delay time
                );
    if(re<0)
    {         cout<<"avformat_open_input err"<<endl;         exit (- 1);     }


    av_dump_format(fmt_ctx, 0, url, 0);//imprime as informações do arquivo

    re = avformat_find_stream_info(fmt_ctx, 0);//Obter informações do stream
    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);//Encontre o "melhor" stream no arquivo. O melhor fluxo é determinado com base em várias heurísticas, pois é mais provável que o usuário esperasse. Se o parâmetro do decodificador for não nulo, av_find_best_stream encontrará o decodificador padrão para o codec do fluxo; fluxos para os quais nenhum decodificador pode ser encontrado serão ignorados.
    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);//Encontre um decodificador registrado com um ID de codec correspondente.

    AVCodecContext *dec_ctx=avcodec_alloc_context3(av_dec);//Aloca um AVCodecContext e define seus campos com valores padrão. A estrutura resultante deve ser liberada usando avcodec_free_context().

    re=avcodec_parameters_to_context(dec_ctx,video_stream->codecpar); //Preenche o contexto do codec de acordo com os valores dos parâmetros do codec fornecidos. No codec, quaisquer campos alocados que tenham um campo correspondente no 'par' serão liberados e substituídos por uma cópia do campo correspondente no par. Os campos que não possuem um campo correspondente no codec não são modificados.
    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;         saída(-1);     }



    FILE *output_video_file=fopen(out,"wb");
    if(!output_video_file)
    {         cout<<"fopen(out,wb) err"<<endl;         saída(-1);     }


    av_dump_format(fmt_ctx,0,url,0); //Imprime as informações do arquivo, que são diferentes das anteriores
    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) //Retorna o próximo quadro do stream. Esta função retorna o que está armazenado no arquivo e não verifica se o decodificador possui um quadro válido. Ele divide o conteúdo armazenado no arquivo em quadros e retorna um quadro para cada chamada. Ele não omite dados inválidos entre quadros válidos para fornecer ao decodificador o máximo de informações possíveis para decodificar. Se for bem-sucedido, o pacote retornado é contado por referência (pkt->buf set) e válido indefinidamente. Quando o pacote não for mais necessário, ele deve ser liberado usando av_packet_unref(). Para vídeo, um pacote contém apenas um quadro. Para áudio, se cada quadro tiver um tamanho fixo conhecido (como dados PCM ou ADPCM), ele conterá um número de quadro inteiro. Se o quadro de áudio tiver um tamanho variável (por exemplo, áudio MPEG), ele conterá um quadro. pkt->pts, pkt->dts e pkt->duration são sempre definidos com os valores corretos no AVStream. Unidades time_base (adivinhe se o formato não puder fornecê-las). pkt->pts pode ser AV_NOPTS_VALUE se o formato de vídeo tiver b-frames, então é melhor confiar em pkt->dts se você não descompactar o payload.
    {         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;                     quebrar;                 }                //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); acima está a função de gravação do arquivo             }






        }

        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;


    }

fim:
    return a.exec();

}
/*
 O arquivo out.yuv gerado é testado com o seguinte comando. Preste atenção na resolução do arquivo de vídeo. Diferentes resoluções precisam ser ajustadas, como 1920x800, 640x320, etc. ffplay -f
rawvideo -video_size 1920x800 out. sim
*/
 

おすすめ

転載: blog.csdn.net/wangz76/article/details/125584185