gpt4 book ai didi

FFMPEG 转码器产生损坏的视频

转载 作者:行者123 更新时间:2023-12-04 22:57:07 37 4
gpt4 key购买 nike

我有以下代码来转码与 FFMPEG transcoding example 密切相关的视频.
但是它产生了如图所示的损坏视频:
Big Buck Bunny broken 1
Big Buck Bunny broken 2
似乎 i 帧已正确解码,但 p 和 b 帧无序?我以为 av_interleaved_write_frame()会为我纠正这一点。似乎 libx264 也没有像我认为的那样创建任何额外数据。
有人可以帮我弄清楚为什么吗?
非常感谢

#include <stdbool.h>
#include <stdio.h>

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libavutil/mathematics.h>
#include <libavutil/opt.h>

#define DEBUG(level, format, ...) fprintf(stderr, format "\n", ##__VA_ARGS__)

#define stringify2(var) #var
#define stringify(var) stringify2(var)

#define RASSERT(cond, ...) do { \
if (!(cond)) { \
DEBUG(LOG_FATAL, __FILE__ ":" stringify(__LINE__) " " "Assertion failed! " #cond ". " __VA_ARGS__); \
abort(); \
} \
} while (0)

#define FFCHECK(ret, func) RASSERT(ret == 0, #func " failed: %s (%d)", av_err2str(ret), ret)

typedef struct decode_context {
AVFormatContext *format;
AVCodecContext *videoCodec;
AVCodecContext *audioCodec;
AVStream *videoStream;
AVStream *audioStream;
} decode_context_t;

typedef struct encode_context {
AVFormatContext *format;
AVCodecContext *videoCodec;
AVCodecContext *audioCodec;
AVStream *videoStream;
AVStream *audioStream;
} encode_context_t;

void open_input(decode_context_t *dec, const char *file) {
int ret;

ret = avformat_open_input(&dec->format, file, NULL, NULL);
FFCHECK(ret, "avformat_open_input()");

ret = avformat_find_stream_info(dec->format, NULL);
FFCHECK(ret, "avformat_find_stream_info()");

for (unsigned int i = 0; i < dec->format->nb_streams; ++i) {
AVStream * stream = dec->format->streams[i];
enum AVMediaType type = stream->codecpar->codec_type;
switch (type) {
case AVMEDIA_TYPE_VIDEO:
if (dec->videoStream)
break;

dec->videoStream = stream;
break;

case AVMEDIA_TYPE_AUDIO:
dec->audioStream = stream;

if (dec->audioStream)
break;

break;

default:
break;
}
}

RASSERT(dec->videoStream != NULL, "Didn't find video stream");

const AVCodec * codec = avcodec_find_decoder(dec->videoStream->codecpar->codec_id);

RASSERT(codec, "Failed to find decoder");

dec->videoCodec = avcodec_alloc_context3(codec);
RASSERT(dec->videoCodec, "avcodec_alloc_context3() failed");

ret = avcodec_parameters_to_context(dec->videoCodec, dec->videoStream->codecpar);
FFCHECK(ret, "avcodec_parameters_to_context()");

dec->videoCodec->framerate = av_guess_frame_rate(dec->format, dec->videoStream, NULL);

ret = avcodec_open2(dec->videoCodec, codec, NULL);
FFCHECK(ret, "avcodec_open2()");
}

void open_output(encode_context_t *enc, const char *file, decode_context_t *dec) {
int ret;

ret = avformat_alloc_output_context2(&enc->format, NULL, NULL, file);
FFCHECK(ret, "avformat_alloc_output_context2()");

enc->videoStream = avformat_new_stream(enc->format, NULL);
RASSERT(enc->videoStream, "avformat_new_stream() failed");

enc->videoStream->id = enc->format->nb_streams - 1;

const AVCodec *codec = avcodec_find_encoder_by_name("libx264");
RASSERT(codec, "Failed to find encoder");

enc->videoCodec = avcodec_alloc_context3(codec);
RASSERT(enc->videoCodec, "avcodec_alloc_context3() failed");

enc->videoCodec->bit_rate = 400000;
enc->videoCodec->width = dec->videoCodec->width;
enc->videoCodec->height = dec->videoCodec->height;
enc->videoCodec->sample_aspect_ratio = dec->videoCodec->sample_aspect_ratio;
enc->videoCodec->time_base = av_inv_q(dec->videoCodec->framerate);
//enc->videoCodec->gop_size = 12;
//enc->videoCodec->max_b_frames = 2;
enc->videoCodec->pix_fmt = dec->videoCodec->pix_fmt;
enc->videoCodec->framerate = dec->videoCodec->framerate;

if (codec->id == AV_CODEC_ID_H264) {
av_opt_set(enc->videoCodec->priv_data, "preset", "slow", 0);
av_opt_set(enc->videoCodec->priv_data, "profile", "high", 0);
av_opt_set(enc->videoCodec->priv_data, "level", "4.1", 0);
}

if (enc->format->flags & AVFMT_GLOBALHEADER)
enc->videoCodec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

ret = avcodec_open2(enc->videoCodec, codec, NULL);
FFCHECK(ret, "avcodec_open2()");

ret = avcodec_parameters_from_context(enc->videoStream->codecpar, enc->videoCodec);
FFCHECK(ret, "avcodec_parameters_from_context()");
//enc->videoStream->time_base = enc->videoCodec->time_base;
//enc->videoStream->codecpar->extradata = enc->videoCodec->extradata;
//enc->videoStream->codecpar->extradata_size = enc->videoCodec->extradata_size;

av_dump_format(enc->format, 0, file, 1);

ret = avio_open(&enc->format->pb, file, AVIO_FLAG_WRITE);
FFCHECK(ret, "avio_open()");

ret = avformat_write_header(enc->format, NULL);
FFCHECK(ret, "avformat_write_header()");
}

int main(int argc, const char * argv[]) {
int ret;

if (argc < 3) {
fprintf(stderr, "%s input output\n", argv[0]);
return 1;
}

decode_context_t dec_ctx = {};
decode_context_t *dec = &dec_ctx;
encode_context_t enc_ctx = {};
encode_context_t *enc = &enc_ctx;

open_input(dec, argv[1]);

open_output(enc, argv[2], dec);

while (true) {
AVPacket *packet = av_packet_alloc();
ret = av_read_frame(dec->format, packet);
if (ret < 0)
break;

if (packet->stream_index == dec->videoStream->index) {
ret = avcodec_send_packet(dec->videoCodec, packet);
if (ret == AVERROR(EAGAIN)) {
AVFrame * frame = av_frame_alloc();
while (true) {
ret = avcodec_receive_frame(dec->videoCodec, frame);
if (ret == AVERROR(EAGAIN))
break;
FFCHECK(ret, "avcodec_receive_frame()");

ret = avcodec_send_frame(enc->videoCodec, frame);
if (ret == AVERROR(EAGAIN)) {
AVPacket *pkt = av_packet_alloc();
while (true) {
ret = avcodec_receive_packet(enc->videoCodec, pkt);
if (ret == AVERROR(EAGAIN))
break;
FFCHECK(ret, "avcodec_receive_packet()");

pkt->stream_index = enc->videoStream->id;
av_packet_rescale_ts(pkt, dec->videoStream->time_base, enc->videoStream->time_base);

ret = av_interleaved_write_frame(enc->format, pkt);
FFCHECK(ret, "av_interleaved_write_frame()");
}
av_packet_free(&pkt);
}
}
av_frame_free(&frame);
} else {
FFCHECK(ret, "avcodec_send_packet()");
}
} else if (packet->stream_index == dec->audioStream->index) {
// Deal with audio
}

av_packet_free(&packet);
}

ret = av_write_trailer(enc->format);
FFCHECK(ret, "av_write_trailer()");

ret = avio_close(enc->format->pb);
FFCHECK(ret, "avio_close()");

// Close some more stuff

return 0;
}

最佳答案

在考虑了更多之后,我意识到我什至不确定我的解码器是否正确。对转码示例的另一项彻底检查揭示了行为上的微小差异。
实际上,我正在这样做:

while (true) {
ret = avcodec_send_packet(dec->videoCodec, packet);
if (ret != AVERROR(EAGAIN)) {
continue;
}

ret = avcodec_receive_frame(dec->videoCodec, frame);
}
删除 continue 并立即尝试从解码器接收帧效果更好,并解决了我的问题。
while (true) {
ret = avcodec_send_packet(dec->videoCodec, packet);
if (ret != 0)
abort();

ret = avcodec_receive_frame(dec->videoCodec, frame);
}
我在编码方面也有同样的错误,所以我也在那里修复了它。

关于FFMPEG 转码器产生损坏的视频,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69484611/

37 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com