c++ - ffmpeg 调用 avcodec_send_packet 失败

标签 c++ c ffmpeg

Windows 10 x64, ffmpeg: 3.1, 预建 dll

这里绝对是新手。

我正在尝试一个非常基本的案例来解码视频文件中的帧,但每次尝试都失败了。最终的代码片段如下所示:

#define __STDC_CONSTANT_MACROS
extern "C" {
#include<libavutil/avutil.h>
#include<libavutil/imgutils.h>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
}

#include <iostream>


int main(int argc, char **argv) {
    AVFormatContext* ctx_format = nullptr;
    AVCodecContext* ctx_codec = nullptr;
    AVCodec* codec = nullptr;
    AVFrame* frame = av_frame_alloc();
    int stream_idx;
    SwsContext* ctx_sws = nullptr;
    const char* fin = argv[1];
    AVStream *vid_stream = nullptr;
    AVPacket* pkt = av_packet_alloc();

    av_register_all();

    if (int ret = avformat_open_input(&ctx_format, fin, nullptr, nullptr) != 0) {
        std::cout << 1 << std::endl;
        return ret;
    }
    if (avformat_find_stream_info(ctx_format, nullptr) < 0) {
        std::cout << 2 << std::endl;
        return -1; // Couldn't find stream information
    }
    av_dump_format(ctx_format, 0, fin, false);

    for (int i = 0; i < ctx_format->nb_streams; i++)
        if (ctx_format->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
            stream_idx = i;
            vid_stream = ctx_format->streams[i];
            break;
    }
    if (vid_stream == nullptr) {
        std::cout << 4 << std::endl;
        return -1;
    }

    codec = avcodec_find_decoder(vid_stream->codecpar->codec_id);
    if (!codec) {
        fprintf(stderr, "codec not found\n");
        exit(1);
    }
    ctx_codec = avcodec_alloc_context3(codec);

    if(avcodec_parameters_to_context(ctx_codec, vid_stream->codecpar)<0)
        std::cout << 512;
    if (avcodec_open2(ctx_codec, codec, nullptr)<0) {
        std::cout << 5;
        return -1;
    }

    //av_new_packet(pkt, pic_size);

    while(av_read_frame(ctx_format, pkt) >= 0){
        int ret = avcodec_send_packet(ctx_codec, pkt);
        if (ret < 0 || ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
            std::cout << "avcodec_send_packet: " << ret << std::endl;
            break;
        }
        if (pkt->stream_index == stream_idx) {
            while (ret  >= 0) {
                ret = avcodec_receive_frame(ctx_codec, frame);
                if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
                    //std::cout << "avcodec_receive_frame: " << ret << std::endl;
                    break;
                }
                std::cout << "frame: " << ctx_codec->frame_number << std::endl;
            }
        }
        av_packet_unref(pkt);
    }

    avformat_close_input(&ctx_format);
    av_packet_unref(pkt);
    avcodec_free_context(&ctx_codec);
    avformat_free_context(ctx_format);
    return 0;
}

它基本上保留所有默认值,并尝试从中读取数据包和解码帧。 avcodec_send_packet 在 while 循环的第一轮或第二轮调用中总是返回负值

flv 的输出:

> .\streamer_test.exe .\SampleVideo_360x240_5mb.flv
Input #0, flv, from '.\SampleVideo_360x240_5mb.flv':
  Metadata:
    encoder         : Lavf53.24.2
  Duration: 00:00:53.32, start: 0.000000, bitrate: 787 kb/s
    Stream #0:0: Audio: aac (LC), 48000 Hz, 5.1, fltp, 384 kb/s
    Stream #0:1: Video: flv1, yuv420p, 320x240, 500 kb/s, 1k fps, 25 tbr, 1k tbn
frame: 1
[flv @ 000001545edb66c0] Bad picture start code
[flv @ 000001545edb66c0] header damaged
avcodec_send_packet: -1094995529

mp4 输出:

> .\streamer_test.exe .\SampleVideo_360x240_10mb.mp4
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '.\SampleVideo_360x240_10mb.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    creation_time   : 1970-01-01T00:00:00.000000Z
    encoder         : Lavf53.24.2
  Duration: 00:02:05.95, start: 0.000000, bitrate: 669 kb/s
    Stream #0:0(und): Video: h264 (Main) (avc1 / 0x31637661), yuv420p, 320x240 [SAR 1:1 DAR 4:3], 282 kb/s, 15 fps, 15 t
br, 15360 tbn, 30 tbc (default)
    Metadata:
      creation_time   : 1970-01-01T00:00:00.000000Z
      handler_name    : VideoHandler
    Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, 5.1, fltp, 383 kb/s (default)
    Metadata:
      creation_time   : 1970-01-01T00:00:00.000000Z
      handler_name    : SoundHandler
[h264 @ 000002e2446a6cc0] Invalid NAL unit size (17191968 > 1007).
[h264 @ 000002e2446a6cc0] Error splitting the input into NAL units.
avcodec_send_packet: -1094995529

mkv 的输出:

> .\streamer_test.exe .\SampleVideo_1280x720_2mb.mkv
Input #0, matroska,webm, from '.\SampleVideo_1280x720_2mb.mkv':
  Metadata:
    ENCODER         : Lavf53.24.2
  Duration: 00:00:10.65, bitrate: 1575 kb/s
    Stream #0:0: Video: mpeg4 (Simple Profile), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 25 fps, 25 tbr, 1k tbn, 25 tbc (de
fault)
    Stream #0:1: Audio: aac (LC), 48000 Hz, 5.1, fltp (default)
frame: 1
[mpeg4 @ 000001166798ede0] header damaged
avcodec_send_packet: -1

所以我猜 avcodec_send_packet 调用一定有问题,但无法弄清楚缺少什么。关于原因的任何想法?非常感谢您的帮助!

最佳答案

调用av_read_frame会返回音频/视频流,你需要用不同的AVCodecContext来处理它们。

因为你用avcodec_send_packet发送音频流,但是你的 AVCodecContext 用于视频流,你得到了错误。

看来你只对视频流感兴趣。

更改您的代码

while(av_read_frame(ctx_format, pkt) >= 0){
    int ret = avcodec_send_packet(ctx_codec, pkt);
    if (ret < 0 || ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
        std::cout << "avcodec_send_packet: " << ret << std::endl;
        break;
    }
    if (pkt->stream_index == stream_idx) {
        while (ret  >= 0) {
            ret = avcodec_receive_frame(ctx_codec, frame);
            if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
                //std::cout << "avcodec_receive_frame: " << ret << std::endl;
                break;
            }
            std::cout << "frame: " << ctx_codec->frame_number << std::endl;
        }
    }
    av_packet_unref(pkt);
}

以下内容将起作用。

while(av_read_frame(ctx_format, pkt) >= 0){
    if (pkt->stream_index == stream_idx) {
        int ret = avcodec_send_packet(ctx_codec, pkt);
        if (ret < 0 || ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
            std::cout << "avcodec_send_packet: " << ret << std::endl;
            break;
        }
        while (ret  >= 0) {
            ret = avcodec_receive_frame(ctx_codec, frame);
            if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
                //std::cout << "avcodec_receive_frame: " << ret << std::endl;
                break;
            }
            std::cout << "frame: " << ctx_codec->frame_number << std::endl;
        }
    }
    av_packet_unref(pkt);
}

使用ffmpeg解码时,记得针对不同的流成对调用avcodec_send_packet/avcodec_receive_frame

关于c++ - ffmpeg 调用 avcodec_send_packet 失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44711921/

相关文章:

c++ - olly 调试器找不到引用的文本

c - 汇编代码的长度可以表示执行速度?

c - 如果我们同时使用两个传感器,为什么它会向我们的电脑发送错误数据?

c - 查找数组中的最小数字

ffmpeg - 如何在不重新编码的情况下将 h.265 视频加速 1000 倍

python - 如何使用 youtube-dl 在 discord.py bot 上播放整个 youtube 播放列表

ffmpeg更改视频文件中的时间码元数据

c++ - 将字符串从 UTF-8 转换为 ISO-8859-1

c++ - zeromq pub sub 上丢失的消息

c++ - opencv 中 .at<uchar> 和 static_cast<uchar> 的区别?