Ffmpeg 使用libavcodec将视频解码为YUV422 我想编写一个C++应用程序,打开MP4文件并将其解码为YUV422文件。 我根据libavcodec教程编写了一些代码,但我找不到将位深度和格式设置为YUV422的位置

Ffmpeg 使用libavcodec将视频解码为YUV422 我想编写一个C++应用程序,打开MP4文件并将其解码为YUV422文件。 我根据libavcodec教程编写了一些代码,但我找不到将位深度和格式设置为YUV422的位置,ffmpeg,rgb,video-processing,yuv,libavcodec,Ffmpeg,Rgb,Video Processing,Yuv,Libavcodec,下面是我写的一些代码 void read_video_stream(AVFormatContext *pFormatContext, AVCodec *pCodec, AVCodecParameters *pCodecParameters, int video_stream_index) { AVCodecContext *pCodecContext = avcodec_alloc_context3(pCodec); std::uni

下面是我写的一些代码

void read_video_stream(AVFormatContext *pFormatContext, AVCodec *pCodec, AVCodecParameters *pCodecParameters,
                       int video_stream_index)
{
    AVCodecContext *pCodecContext = avcodec_alloc_context3(pCodec);
    std::unique_ptr<AVCodecContext, av_deleter> ctx_guard(pCodecContext);
    if (!pCodecContext) {
        return;
    }
    if (avcodec_parameters_to_context(pCodecContext, pCodecParameters) < 0) {
        return;
    }
    // i tried setting it here
    if (avcodec_open2(pCodecContext, pCodec, NULL) < 0) {
        return;
    }
    while (true) {
        std::unique_ptr<AVPacket, std::function<void(AVPacket*)>> packet{
                        new AVPacket,
                        [](AVPacket* p){ av_packet_unref(p); delete p; }};

        av_init_packet(packet.get());
        int response = av_read_frame(pFormatContext, packet.get());
        if (AVERROR_EOF == response) {
            std::cout << "EOF\n";
        }
        else if (response < 0) {
            std::cout << "Error " << response;
            return;
        }
        if (packet->stream_index != video_stream_index) {
            continue;
        }
        response = avcodec_send_packet(pCodecContext, packet.get());
        if (response < 0) {
            std::cout << "Error while sending a packet to the decoder: " << response;
            return;
        }
        while (response >= 0) {
            std::shared_ptr<AVFrame> pFrame{  av_frame_alloc(), AVFrameDeleter};
            response = avcodec_receive_frame(pCodecContext, pFrame.get());
            if (response == AVERROR(EAGAIN)) {
                continue;
            }
            if (response == AVERROR_EOF) {
                std::cerr << "got to last frame\n";
                return;
            }
            else if (response < 0) {
                std::cerr << "Error while receiving a frame from the decoder: " << response;
                return;
            }

            if (response >= 0) {
                // copy line to cyclic buffer
                cb.push_back(std::move(pFrame));

            }
        }
    }
}
void read\u video\u流(AVFormatContext*pFormatContext、AVCodec*pCodec、AVCodecParameters*pCodecParameters、,
int视频(流索引)
{
AVCodecContext*pCodecContext=avcodec\u alloc\u context3(pCodec);
std::唯一的ctx保护(pCodecContext);
如果(!pCodecContext){
返回;
}
if(avcodec_参数_到_上下文(pCodecContext,pCodecParameters)<0){
返回;
}
//我试着把它放在这里
if(avcodec_open2(pCodecContext,pCodec,NULL)<0){
返回;
}
while(true){
std::唯一的ptr数据包{
新AVPacket,
[](AVPacket*p){avu packet_unref(p);删除p;};
av_init_数据包(packet.get());
int response=av_read_frame(pFormatContext,packet.get());
如果(平均误差=响应){

std::cout该评论说:“你不需要解码成特定的格式。你需要解码成流的编码格式。如果你想要一种不同的格式,你可以在决定后转换(使用swacale)。”

我将填补空白。大多数电影文件(mp4)最初是YUV420P格式,因此这是解码后得到的格式。但这可能不同于,因此我将其称为解码像素格式。使用解码像素格式获得AVFrame后,可以使用
swscale()
函数将其转换为任何其他像素格式

像素格式转换(使用
swscale()
)需要两件事:

1) 设置缩放器上下文。在FFmpeg中,像素格式转换和缩放是通过相同的函数完成的。保持两个大小相同,就不会进行缩放,只需进行转换

除非参数已更改且不再有效,否则无需多次执行此操作:

SwsContext *swsContext = sws_getContext(src_width, src_height, src_pixfmt,
                                        dst_width, dst_height, dst_pixfmt,
                                        SWS_BILINEAR, NULL, NULL, NULL);
示例
src\u pixfmt
AV\u PIX\u FMT\u YUV420P

示例
dst\u pixfmt
AV\u PIX\u FMT\u YUV422P
AV\u PIX\u FMT\u UYVY422

SWS_双线性
是一种缩放算法。当需要缩放时,你可能需要这个点。他们说双线性适合于放大,双三次适合于缩小。我在这个领域不是专家。但我知道双线性比其他许多算法工作得更好更快

2) 要进行转换,您需要以下内容:

AVFrame *dstframe = av_frame_alloc();
if (dstframe == NULL)
{
    fprintf(stderr, "Error: av_frame_alloc() failed.\n");
    exit(EXIT_FAILURE);
}

dstframe->format = AV_PIX_FMT_UYVY422; /* choose same format set on sws_getContext() */
dstframe->width  = srcframe->width; /* must match sizes as on sws_getContext() */
dstframe->height = srcframe->height; /* must match sizes as on sws_getContext() */
int ret = av_frame_get_buffer(dstframe, 32);
if (ret < 0)
{
    fprintf(stderr, "Error: could not allocate the video frame data\n");
    exit(EXIT_FAILURE);
}

/* do the conversion */
ret = sws_scale(swsContext,             /* SwsContext* on step (1) */
                srcframe->data,         /* srcSlice[] from decoded AVFrame */
                srcframe->linesize,     /* srcStride[] from decoded AVFrame */
                0,                      /* srcSliceY   */
                src_height,             /* srcSliceH  from decoded AVFrame */
                dstframe->data,         /* dst[]       */
                dstframe->linesize);    /* dstStride[] */

if (ret < 0)
{
    /* error handling */
}
AVFrame*dstframe=av_frame_alloc();
if(dstframe==NULL)
{
fprintf(stderr,“错误:av_frame_alloc()失败。\n”);
退出(退出失败);
}
dstframe->format=AV_PIX_FMT_UYVY422;/*选择在sws_getContext()上设置的相同格式*/
dstframe->width=srcframe->width;/*必须与sws_getContext()上的大小匹配*/
dstframe->height=srcframe->height;/*必须与sws_getContext()上的大小匹配*/
int-ret=av_-frame_-get_缓冲区(dstframe,32);
如果(ret<0)
{
fprintf(stderr,“错误:无法分配视频帧数据\n”);
退出(退出失败);
}
/*进行转换*/
ret=sws_刻度(swsContext,/*swsContext*在步骤(1)上)*/
srcframe->data,/*srcsicle[]来自解码的AVFrame*/
srcframe->linesize,/*srcStride[]来自解码的AVFrame*/
0,/*src切片*/
src_高度,/*srcSliceH来自解码的AVFrame*/
dst帧->数据,/*dst[]*/
dstframe->linesize);/*dstStride[]*/
如果(ret<0)
{
/*错误处理*/
}
成功转换后,您将在
dstframe
上获得所需内容

在此处查看更多格式、函数和参数的详细信息:


希望这能有所帮助。

评论说“你不需要解码成特定的格式。你需要解码成流的编码格式。如果你想要一种不同的格式,你可以在决定后转换(使用swacale)。”

我将填补空白。大多数电影文件(mp4)最初是YUV420P格式,因此这是解码后得到的格式。但这可能不同于,因此我将其称为解码像素格式。使用解码像素格式获得AVFrame后,可以使用
swscale()
函数将其转换为任何其他像素格式

像素格式转换(使用
swscale()
)需要两件事:

1) 设置缩放器上下文。在FFmpeg中,像素格式转换和缩放是通过相同的函数完成的。保持两个大小相同,就不会进行缩放,只需进行转换

除非参数已更改且不再有效,否则无需多次执行此操作:

SwsContext *swsContext = sws_getContext(src_width, src_height, src_pixfmt,
                                        dst_width, dst_height, dst_pixfmt,
                                        SWS_BILINEAR, NULL, NULL, NULL);
示例
src\u pixfmt
AV\u PIX\u FMT\u YUV420P

示例
dst\u pixfmt
AV\u PIX\u FMT\u YUV422P
AV\u PIX\u FMT\u UYVY422

SWS_双线性
是一种缩放算法。当需要缩放时,你可能需要这个点。他们说双线性适合于放大,双三次适合于缩小。我在这个领域不是专家。但我知道双线性比其他许多算法工作得更好更快

2) 要进行转换,您需要以下内容:

AVFrame *dstframe = av_frame_alloc();
if (dstframe == NULL)
{
    fprintf(stderr, "Error: av_frame_alloc() failed.\n");
    exit(EXIT_FAILURE);
}

dstframe->format = AV_PIX_FMT_UYVY422; /* choose same format set on sws_getContext() */
dstframe->width  = srcframe->width; /* must match sizes as on sws_getContext() */
dstframe->height = srcframe->height; /* must match sizes as on sws_getContext() */
int ret = av_frame_get_buffer(dstframe, 32);
if (ret < 0)
{
    fprintf(stderr, "Error: could not allocate the video frame data\n");
    exit(EXIT_FAILURE);
}

/* do the conversion */
ret = sws_scale(swsContext,             /* SwsContext* on step (1) */
                srcframe->data,         /* srcSlice[] from decoded AVFrame */
                srcframe->linesize,     /* srcStride[] from decoded AVFrame */
                0,                      /* srcSliceY   */
                src_height,             /* srcSliceH  from decoded AVFrame */
                dstframe->data,         /* dst[]       */
                dstframe->linesize);    /* dstStride[] */

if (ret < 0)
{
    /* error handling */
}
AVFrame*dstframe=av_frame_alloc();
if(dstframe==NULL)
{
fprintf(stderr,“错误:av_frame_alloc()失败。\n”);
退出(退出失败);
}
dstframe->format=AV_PIX_FMT_UYVY422;/*选择在sws_getContext()上设置的相同格式*/
dstframe->width=srcframe->width;/*必须与sws_getContext()上的大小匹配*/
dstframe->height=srcframe->height;/*必须与sws_getContext()上的大小匹配*/
int-ret=av_-frame_-get_缓冲区(dstframe,32);
如果(ret<0)
{
fprintf(stderr,“错误:无法分配视频帧数据\n”);
退出(退出失败);
}
/*进行转换*/
ret=sws_刻度(swsContext,/*swsContext*在步骤(1)上)*