- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在编写一个应用程序,它从输入文件(任何编解码器、任何容器)解码单个视频流,进行一堆图像处理,并将结果编码到输出文件(单个视频流、Quicktime RLE、MOV)。我正在使用 ffmpeg 的 libav 3.1.5(目前是 Windows 版本,但该应用程序将是跨平台的)。
输入和输出帧之间有 1:1 的对应关系,我希望输出中的帧时序与输入相同。我真的很难做到这一点。所以我的一般问题是: 我如何可靠地(如在所有输入情况下)将输出帧时序设置为与输入相同?
我花了很长时间才通过 API 并达到我现在的地步。我整理了一个最小的测试程序来使用:
#include <cstdio>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
}
using namespace std;
struct DecoderStuff {
AVFormatContext *formatx;
int nstream;
AVCodec *codec;
AVStream *stream;
AVCodecContext *codecx;
AVFrame *rawframe;
AVFrame *rgbframe;
SwsContext *swsx;
};
struct EncoderStuff {
AVFormatContext *formatx;
AVCodec *codec;
AVStream *stream;
AVCodecContext *codecx;
};
template <typename T>
static void dump_timebase (const char *what, const T *o) {
if (o)
printf("%s timebase: %d/%d\n", what, o->time_base.num, o->time_base.den);
else
printf("%s timebase: null object\n", what);
}
// reads next frame into d.rawframe and d.rgbframe. returns false on error/eof.
static bool read_frame (DecoderStuff &d) {
AVPacket packet;
int err = 0, haveframe = 0;
// read
while (!haveframe && err >= 0 && ((err = av_read_frame(d.formatx, &packet)) >= 0)) {
if (packet.stream_index == d.nstream) {
err = avcodec_decode_video2(d.codecx, d.rawframe, &haveframe, &packet);
}
av_packet_unref(&packet);
}
// error output
if (!haveframe && err != AVERROR_EOF) {
char buf[500];
av_strerror(err, buf, sizeof(buf) - 1);
buf[499] = 0;
printf("read_frame: %s\n", buf);
}
// convert to rgb
if (haveframe) {
sws_scale(d.swsx, d.rawframe->data, d.rawframe->linesize, 0, d.rawframe->height,
d.rgbframe->data, d.rgbframe->linesize);
}
return haveframe;
}
// writes an output frame, returns false on error.
static bool write_frame (EncoderStuff &e, AVFrame *inframe) {
// see note in so post about outframe here
AVFrame *outframe = av_frame_alloc();
outframe->format = inframe->format;
outframe->width = inframe->width;
outframe->height = inframe->height;
av_image_alloc(outframe->data, outframe->linesize, outframe->width, outframe->height,
AV_PIX_FMT_RGB24, 1);
//av_frame_copy(outframe, inframe);
static int count = 0;
for (int n = 0; n < outframe->width * outframe->height; ++ n) {
outframe->data[0][n*3+0] = ((n+count) % 100) ? 0 : 255;
outframe->data[0][n*3+1] = ((n+count) % 100) ? 0 : 255;
outframe->data[0][n*3+2] = ((n+count) % 100) ? 0 : 255;
}
++ count;
AVPacket packet;
av_init_packet(&packet);
packet.size = 0;
packet.data = NULL;
int err, havepacket = 0;
if ((err = avcodec_encode_video2(e.codecx, &packet, outframe, &havepacket)) >= 0 && havepacket) {
packet.stream_index = e.stream->index;
err = av_interleaved_write_frame(e.formatx, &packet);
}
if (err < 0) {
char buf[500];
av_strerror(err, buf, sizeof(buf) - 1);
buf[499] = 0;
printf("write_frame: %s\n", buf);
}
av_packet_unref(&packet);
av_freep(&outframe->data[0]);
av_frame_free(&outframe);
return err >= 0;
}
int main (int argc, char *argv[]) {
const char *infile = "wildlife.wmv";
const char *outfile = "test.mov";
DecoderStuff d = {};
EncoderStuff e = {};
av_register_all();
// decoder
avformat_open_input(&d.formatx, infile, NULL, NULL);
avformat_find_stream_info(d.formatx, NULL);
d.nstream = av_find_best_stream(d.formatx, AVMEDIA_TYPE_VIDEO, -1, -1, &d.codec, 0);
d.stream = d.formatx->streams[d.nstream];
d.codecx = avcodec_alloc_context3(d.codec);
avcodec_parameters_to_context(d.codecx, d.stream->codecpar);
avcodec_open2(d.codecx, NULL, NULL);
d.rawframe = av_frame_alloc();
d.rgbframe = av_frame_alloc();
d.rgbframe->format = AV_PIX_FMT_RGB24;
d.rgbframe->width = d.codecx->width;
d.rgbframe->height = d.codecx->height;
av_frame_get_buffer(d.rgbframe, 1);
d.swsx = sws_getContext(d.codecx->width, d.codecx->height, d.codecx->pix_fmt,
d.codecx->width, d.codecx->height, AV_PIX_FMT_RGB24,
SWS_POINT, NULL, NULL, NULL);
//av_dump_format(d.formatx, 0, infile, 0);
dump_timebase("in stream", d.stream);
dump_timebase("in stream:codec", d.stream->codec); // note: deprecated
dump_timebase("in codec", d.codecx);
// encoder
avformat_alloc_output_context2(&e.formatx, NULL, NULL, outfile);
e.codec = avcodec_find_encoder(AV_CODEC_ID_QTRLE);
e.stream = avformat_new_stream(e.formatx, e.codec);
e.codecx = avcodec_alloc_context3(e.codec);
e.codecx->bit_rate = 4000000; // arbitrary for qtrle
e.codecx->width = d.codecx->width;
e.codecx->height = d.codecx->height;
e.codecx->gop_size = 30; // 99% sure this is arbitrary for qtrle
e.codecx->pix_fmt = AV_PIX_FMT_RGB24;
e.codecx->time_base = d.stream->time_base; // ???
e.codecx->flags |= (e.formatx->flags & AVFMT_GLOBALHEADER) ? AV_CODEC_FLAG_GLOBAL_HEADER : 0;
avcodec_open2(e.codecx, NULL, NULL);
avcodec_parameters_from_context(e.stream->codecpar, e.codecx);
//av_dump_format(e.formatx, 0, outfile, 1);
dump_timebase("out stream", e.stream);
dump_timebase("out stream:codec", e.stream->codec); // note: deprecated
dump_timebase("out codec", e.codecx);
// open file and write header
avio_open(&e.formatx->pb, outfile, AVIO_FLAG_WRITE);
avformat_write_header(e.formatx, NULL);
// frames
while (read_frame(d) && write_frame(e, d.rgbframe))
;
// write trailer and close file
av_write_trailer(e.formatx);
avio_closep(&e.formatx->pb);
}
write_frame
中分配一个新的缓冲区,而不是直接使用 inframe
,是因为这更能代表我的实际应用程序正在做的事情。我的真实应用程序也在内部使用 RGB24,因此这里进行转换。 outframe
中生成奇怪模式的原因,而不是使用例如av_copy_frame
,是因为我只想要一个用 Quicktime RLE 压缩得很好的测试模式(否则我的测试输入最终会生成一个 1.7GB 的输出文件)。 avcodec_decode_video2
和 avcodec_encode_video2
已被弃用,但不在乎。他们工作得很好,我已经在最新版本的 API 上挣扎了太多,ffmpeg 几乎在每个版本中都会更改他们的 API,我现在真的不想处理 avcodec_send_*
and avcodec_receive_*
。 avcodec_encode_video2
之前完成以刷新一些缓冲区或其他东西,但我对此有点困惑。除非有人想解释让我们暂时忽略它,否则这是一个单独的问题。文档在这一点上与其他所有内容一样含糊不清。 main: d.stream->time_base
:输入视频流时基。 对于我的测试输入文件,这是 1/1000。 main: d.stream->codec->time_base
:不知道这是什么(我永远无法理解为什么 AVStream
有一个 AVCodecContext
字段,不管怎样,当你总是使用你自己的新字段时,你自己的新字段也是 18s12312312313131313131318181314131313131313131313131313131313131313131313131313123 对于我的测试输入文件,这是 1/1000。 codec
:输入编解码器上下文时基。 对于我的测试输入文件,这是 0/1。我应该设置它吗? main: d.codecx->time_base
:我创建的输出流的时基。 我要把它设置成什么? main: e.stream->time_base
:我创建的输出流的已弃用且神秘的编解码器字段的时基。 我是否将其设置为任何内容? main: e.stream->codec->time_base
:我创建的编码器上下文的时基。 我要把它设置成什么? main: e.codecx->time_base
: 数据包读取的解码时间戳。 read_frame: packet.dts
:数据包读取的显示时间戳。 read_frame: packet.pts
:数据包读取的持续时间。 read_frame: packet.duration
:解码原始帧的显示时间戳。 这总是0。为什么它不被解码器读取......? read_frame: d.rawframe->pts
/read_frame: d.rgbframe->pts
: 转换为 RGB 的解码帧的显示时间戳。当前未设置为任何内容。 write_frame: inframe->pts
:从数据包复制的字段,在读取 this post 后发现。它们设置正确,但我不知道它们是否有用。 read_frame: d.rawframe->pkt_*
:正在编码的帧的显示时间戳。 我应该把它设置成什么吗? write_frame: outframe->pts
:来自数据包的计时字段。 我应该设置这些吗?它们似乎被编码器忽略了。 write_frame: outframe->pkt_*
:正在编码的数据包的解码时间戳。 我把它设置成什么? write_frame: packet.dts
:正在编码的数据包的显示时间戳。 我把它设置成什么? write_frame: packet.pts
:数据包被编码的持续时间。 我把它设置成什么? write_frame: packet.duration
是
inframe
:
d.rgbframe
e.stream->time_base = d.stream->time_base
e.codecx->time_base = d.codecx->time_base
设置在 d.rgbframe->pts = packet.dts
read_frame
设置在 outframe->pts = inframe->pts
write_frame
起),段错误。 d.codecx->time_base was 0/1
e.stream->time_base = d.stream->time_base
e.codecx->time_base = d.stream->time_base
设置在 d.rgbframe->pts = packet.dts
read_frame
设置在 outframe->pts = inframe->pts
write_frame
中的所有计时字段设置为 0,这不是我所期望的。 (编辑:原来这是因为 packet
与 av_interleaved_write_frame
不同,它获取数据包的所有权并将其与空白数据交换,并且我在该调用之后打印了值。因此它们不会被忽略。) 0x2919124212334111av_write_frame
e.stream->time_base = d.stream->time_base
e.codecx->time_base = d.stream->time_base
设置在 d.rgbframe->pts = packet.dts
read_frame
中 packet
中的任何 pts/dts/duration 设置为任何内容。 write_frame
e.stream->time_base = d.stream->time_base
e.codecx->time_base = d.stream->time_base
,pkt_pts
,并在pkt_dts
pkt_duration
阅读this post后,所以我试图通过对AVFrame
复制那些一路。 最佳答案
我认为您的问题是时基起初有点令人困惑。
d.stream->time_base: Input video stream time base
.这是输入容器中时间戳的解析。从 av_read_frame
返回的编码帧将具有此分辨率的时间戳。 d.stream->codec->time_base: Not sure what this is
.它是旧的 API,用于 API 兼容性;您正在使用编解码器参数,因此请忽略它。 d.codecx->time_base: Input codec context time-base. For my test input file this is 0/1. Am I supposed to set it?
这是编解码器(与容器相反)的时间戳分辨率。编解码器将假定其输入编码帧在此分辨率下具有时间戳,并且还将在此分辨率下在输出解码帧中设置时间戳。 e.stream->time_base: Time base of the output stream I create
.与解码器 e.stream->codec->time_base
.与 demuxer 相同 - 忽略这个。 e.codecx->time_base
- 与分路器 av_packet_rescale_ts
可以帮助您做到这一点 pts
) 设置为 av_frame_get_best_effort_timestamp
av_rescale_q
或 av_rescale_q_rnd
av_packet_rescale_ts
pts
)。
avcodec_encode_video2
以让编码器知道您已完成并使其输出所有剩余数据(您需要与所有其他数据包一样通过多路复用器)。事实上,你应该反复这样做,直到它停止喷出数据包。有关一些示例,请参阅 ffmpeg 内
doc/examples
文件夹中的编码示例之一。
关于c++ - Libav (ffmpeg) 将解码的视频时间戳复制到编码器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40275242/
我有以下 json: {"results": [{"columns":["room_id","player_name","player_ip"], "types":["integer","text
我在 go 中获取格式不一致的 JSON 文件。例如,我可以有以下内容: {"email": "\"blah.blah@blah.com\""} {"email": "robert@gmail.com
JavaScript中有JSON编码/解码base64编码/解码函数吗? 最佳答案 是的,btoa() 和 atob() 在某些浏览器中可以工作: var enc = btoa("this is so
我在其中一个项目中使用了 Encog,但在解码 One-Of Class 时卡住了。该字段的规范化操作之一是 NormalizationAction.OneOf,它具有三个输出。当我评估时,我想解码预
在我的 previous question关于使用 serialize() 创建对象的 CSV 我从 jmoy 那里得到了一个很好的答案,他推荐了我的序列化文本的 base64 编码。这正是我要找的。
有些事情让我感到困惑 - 为什么 this image在每个浏览器中显示不同? IE9(和 Windows 照片查看器)中的图像: Firefox(和 Photoshop)中的图像: Chrome(和
是否可以在不知道它的类型( JAXBContext.newInstance(clazz) )的情况下解码一个类,或者什么是测试即将到来的正确方法? 我确实收到了从纯文本中解码的消息 - 字符串 传入的
我正在尝试使用 openSSL 库进行 Base64 解码,然后使用 CMS 来验证签名。 下面的代码总是将缓冲区打印为 NULL。 char signed_data[] = "MIIO"; int
我有一个带有 SEL 类型实例变量的类,它是对选择器的引用。在encodeWithCoder/initWithCoder中,如何编码/解码这种类型的变量? 最佳答案 您可以使用 NSStringFro
var url = 'http://www.googleapis.com/customsearch/v1?q=foo&searchType=image'; window.fetch(url) .t
我想知道Android 2.2、2.3和3,4支持的音频/视频格式列表。我也想知道哪些Android版本支持视频编码和解码。我经历了this link,但是关于编码和解码我并不清楚。 任何人的回答都是
我在其中一个项目中使用 Encog,但在解码 One-Of 类时遇到了困难。该字段的规范化操作之一是 NormalizationAction.OneOf,它具有三个输出。当我评估时,我想解码预测值。如
我正在尝试解码现有的 xml 文件,以便我可以正确处理数据,但 XML 结构看起来很奇怪。下面是 xml 示例以及我创建的对象。 11 266 AA1001 1
对 unicode 字符进行 URL 编码的常用方法是将其拆分为 2 %HH 代码。 (\u4161 => %41%61) 但是,unicode在解码时是如何区分的呢?您如何知道 %41%61 是 \
我正在尝试将 json 字符串解码为 Map。 我知道有很多这样的问题,但我需要非常具体的格式。例如,我有 json 字符串: { "map": { "a": "b",
我有一个查询,我认为需要像这样(解码会更大) SELECT firstName, lastName, decode(mathMrk, 80, 'A', mathMrk) as decodeMat
我知道PHP函数encode()和decode(),它们对我来说工作得很好,但我想在url中传递编码字符串,但encode确实返回特殊字符,如“=”、“”' “等等...... 这显然会破坏我的脚本,
我必须解码 Basic bW9uTG9naW46bW9uTW90RGVQYXNz 形式的 http 请求的授权 header 当我解码它时online ,我得到了正确的结果 monLogin:monM
这个问题已经有答案了: Decode Base64 data in Java (21 个回答) 已关闭 8 年前。 我想知道使用哪个库进行 Base64 编码/解码?我需要此功能足够稳定以供生产使用。
我正在尝试从 Arduino BT 解码 []byte,我的连接完美,问题是当我尝试解码数组时。我得到的只是这个字符�(发送的字节数相同)我认为问题出在解码上。我尝试使用 ASCII 字符集,但仍然存
我是一名优秀的程序员,十分优秀!