我尝试用原始H264视频数据创建碎片化的MP4,这样我就可以在互联网浏览器的播放器中播放它了.我的目标是创建实时流媒体系统,媒体服务器将片段化的MP4片段发送到浏览器.服务器将缓冲来自RaspberryPi摄像头的输入数据,该摄像头将视频作为H264帧发送.然后它将复用该视频数据并使其可供客户端使用.浏览器将使用Media Source Extensions播放媒体数据(由服务器复制并通过websocket发送).
出于测试目的,我编写了以下代码片段(使用我在intenet中找到的许多示例):
使用avcodec的C++应用程序,它将原始H264视频复用到碎片MP4并将其保存到文件中:
#define READBUFSIZE 4096
#define IOBUFSIZE 4096
#define ERRMSGSIZE 128
#include <cstdint>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
extern "C"
{
#include <libavformat/avformat.h>
#include <libavutil/error.h>
#include <libavutil/opt.h>
}
enum NalType : uint8_t
{
//NALs containing stream metadata
SEQ_PARAM_SET = 0x7,
PIC_PARAM_SET = 0x8
};
std::vector<uint8_t> outputData;
int mediaMuxCallback(void *opaque, uint8_t *buf, int bufSize)
{
outputData.insert(outputData.end(), buf, buf + bufSize);
return bufSize;
}
std::string getAvErrorString(int errNr)
{
char errMsg[ERRMSGSIZE];
av_strerror(errNr, errMsg, ERRMSGSIZE);
return std::string(errMsg);
} …Run Code Online (Sandbox Code Playgroud) 我将感谢您对以下方面的建议。我正在开发一个基于FFmpeg的libavformat的视频转换器,我需要实现一个精确的查找API。首先,我开发了一个视频流索引器,它只保存每个数据包的呈现时间戳(PTS)。然后我的编码器使用这个索引来寻找视频文件。例如,在此操作之前,我将文件重新混合到 mp4 容器。对于内部没有正确索引或视频根本没有索引的视频,需要进行 Remux。我需要实现按字节查找,当然需要使用之前构建的索引。我尝试了很多方法来实现这一点,但没有成功。也许你知道如何在FFmpeg中实现按字节精确查找?此致。
我正在编写一个使用 ffmpeg 的 libav* 库的 C 程序,并使用Dranger 的教程,我可以正确解码音频和视频。目前,我正在尝试提取字幕。我实际上不想按时解码它们并将它们显示在视频上,而是实际上从容器中提取字幕文本。
例如,在 cli 上,
ffmpeg -i video.mkv -map 0:4 -scodec copy out.ass
Run Code Online (Sandbox Code Playgroud)
会把屁股档案还给我。(由于某种原因,srts 只返回文本。)
我试过搞乱 AVSubtitle、avcodec_decode_subtitle2 等,但它们逐行返回字幕。我想要 srts 中的时间码、ass 中的标题信息等。我想要的只是混合到容器中的整个字幕文本文件。
我正在将 mpeg4 视频混合到 avi 容器。视频流约为 4fps,因此我设置AVCodecContext time_base为 1/4 ( formatContext->streams[0]->codec->time_base...) ,然后重新调整每个帧时间戳,因为原始时间戳以毫秒为单位。我将结果值分配给数据包pts和dts。
当我用 VLC 播放此 avi 时,视频不流畅,并且反复收到以下消息:
avcodec 错误:视频延迟超过 5 秒 -> 丢帧(计算机太慢?)
上面的pts/dts计算有问题吗?
下表演示了时间戳如何重新缩放(原始->重新缩放)
stream: 0 1329471005111->1
stream: 0 1329471005348->2
stream: 0 1329471005588->3
stream: 0 1329471005828->4
stream: 0 1329471006068->5
stream: 0 1329471006308->6
stream: 0 1329471006551->7
stream: 0 1329471006788->8
stream: 0 1329471007028->9
stream: 0 1329471007268->10
stream: 0 1329471007508->11
stream: 0 1329471007748->12
stream: 0 1329471007988->13
stream: 0 1329471008228->14
stream: 0 1329471008468->15
Run Code Online (Sandbox Code Playgroud) 我已经从CDN下载了flv格式的视频(视频H264和音频AAC),并将其重新混合为MP4格式。但是视频受到长度的限制。因此,我已经下载了每个部分的视频:从起点,第1点,第2点开始(通过使用url中的seek参数)。每一点的开始都比上一点的结束早。
使用av_read_framei扫描了所有部分,发现相交的数据包不仅具有相同的大小和顺序,而且它们的dts / pt彼此偏移恒定值。因此,要将视频与从点1开始的视频并置在一起,我必须执行以下操作:
1.在输出文件中创建输出标头
。2.复制起始视频中的所有非相交数据包。
3.通过将常量移动dts值,从点1开始的视频复制所有非相交的数据包
如何使用libav(不是ffmpeg)执行所有这些操作?我阅读了如何在不使用其他libav库的情况下使用libavformat。但libav它不工作,因为那里没有avformat_alloc_output_context2的libav。avconv.c对于像我这样的新手来说,源代码源也太复杂了,无法隔离与流复制操作相关的部分。
有人可以提供我为例:
-开放input_file1和input_file2(仅当需要从通用教程标准程序不同)
-开放和写报头OUTPUT_FILE与同一容器格式和相同的视频和音频格式
-写数据包从input_file1到OUTPUT_FILE直到与例如分组pos == XXX
-写入分组从input_file2到OUTPUT_FILE由恒定值改变它们的DTS(或任何需要的话)
-写正确trailer
我之前在dts中计算时移。
我将代码 avcodec_decode_audio3 更改为 avcodec_decode_audio4 并添加了帧处理。但现在我不能再解码 AAC 帧了。
为什么 avcodec_decode_audio4 返回-22(无效参数)?按照下面的回答,这和AVContext中需要设置的参数有关系吗?
我不得不使用 avcodec_decode_audio4 因为我更新了我的 ffmpeg 然后出现以下错误:
[NULL @ 0xb14f020] Custom get_buffer() for use withavcodec_decode_audio3() detected.
Overriding with avcodec_default_get_buffer
[NULL @ 0xb14f020] Please port your application to avcodec_decode_audio4()
Run Code Online (Sandbox Code Playgroud)
根据avcodec_decode_audio4() 中的缓冲区错误,这是一个回归,除了回到 ffmpeg < 0.8 之外,还有其他解决方案吗?
使用 avcodec_decode_audio4 的解码器:
AVCodec *codec;
AVCodecContext *avCtx;
AVFrame * decoded_frame = NULL;
uint8_t *outbuf = static_cast<uint8_t *>(malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE));
AVPacket avPacket;
main(){
av_register_all();
codec = avcodec_find_decoder(CODEC_ID_AAC);
//set parameters
avCtx = avcodec_alloc_context3(codec);
avCtx->channels = 1; …Run Code Online (Sandbox Code Playgroud) 我正在构建一个 iOS 应用程序,其中需要在后台重新编码和修剪视频。
我不能使用 iOS 库 (AVFoundation),因为它们依赖于 GPU,如果它是后台的,则没有应用程序可以访问 GPU。
由于这个问题,我切换到 FFMpeg 并编译它(与 libx264 一起)并将它集成到我的 iOS 应用程序中。
总结一下我需要的是:
几周后——我经常用头撞墙——我设法:
如果我要通过命令行运行 ffmpeg,我会像这样运行它:
ffmpeg -i input.MOV -ss 0 -t 10 -vf scale=320:240 -c:v libx264 -preset ultrafast -c:a copy output.mkv
Run Code Online (Sandbox Code Playgroud)
我关心的是如何修剪视频?虽然我可以计算我编码/解码的视频帧的数量,并根据 FPS 决定何时停止,但我不能对音频做同样的事情,因为我只是对其进行解复用和重新复用。
理想情况下 - 在缩放视频之前 - 我会运行一个过程,通过将每个流(视频和音频)的 10 秒复制到一个新的视频容器中来修剪视频。
如何通过 AV 库实现这一目标?
我\xe2\x80\x99m 尝试使用 FFMpeg/LibAv 在我的 iOS 应用程序上对视频进行转码。\n我\xe2\x80\x99m 试图完成的是对视频进行转码,以便调整每个帧的大小并可能降低比特率为了在设备中节省宝贵的 MB。
\n\n生成的视频必须可以在所有 iPhone5+ 设备上播放。
\n\n阅读文档后我发现:
\n\n从 FFMpeg 角度来看,我尝试使用 LibAv 实现的目标是:
\n\nffmpeg -i INPUT.MOV -c:v libx264 -preset ultrafast -profile:v baseline -level 3.0 -c:a copy output.MOV\nRun Code Online (Sandbox Code Playgroud)\n\n(生成的文件 - 可以在下面找到 - 如果它是由 FFMpeg 通过命令行生成的\xe2\x80\x99s,则可以在 QuickTime 上播放) …
我目前正在尝试将VPX(VP8/VP9)视频转码为mpeg2视频,并使用mpegts通过UDP进行流式传输.
我已经初始化了所有上下文和流,只要我将其流式传输到ffplay它就可以工作,如果我将流发送到VLC或其他播放器,接收器只显示第一帧而不执行任何其他操作.如果我通过命令行执行相同的操作,它可以完美地工作 - ffmpeg -re -i video.webm -an -f mpegts udp://127.0.0.1:8080
我的输出背景:
this->output_codec_ctx_->codec_type = AVMEDIA_TYPE_VIDEO; // Set media type
this->output_codec_ctx_->pix_fmt = AV_PIX_FMT_YUV420P; // Set stream pixel format
this->output_codec_ctx_->time_base.den = ceil(av_q2d(input_stream->r_frame_rate)); // Add the real video framerate. Eg.: 29.9
this->output_codec_ctx_->time_base.num = 1; // Numerator of the framerate. Eg.: num/29.9
this->output_codec_ctx_->width = input_stream->codecpar->width; // Video width
this->output_codec_ctx_->height = input_stream->codecpar->height; // Video height
this->output_codec_ctx_->bit_rate = 400000; // Video quality
this->output_codec_ctx_->gop_size = 12;
this->output_codec_ctx_->max_b_frames = 2;
this->output_codec_ctx_->framerate = this->input_codec_ctx_->framerate;
this->output_codec_ctx_->sample_aspect_ratio = this->input_codec_ctx_->sample_aspect_ratio;
Run Code Online (Sandbox Code Playgroud)
我的av_dump:
Output …Run Code Online (Sandbox Code Playgroud) 我是 ffmpeg 的第一次用户,我在初始化 mkv muxing 的输出文件时遇到了麻烦。我按照此页面中间的说明进行操作,但它不起作用。
当我调用 avformat_write_header() 函数时,它返回错误代码 -1094995529,这意味着:处理输入时发现无效数据。
当我将输出上下文分配为 mp4 格式(我在这两种情况下都使用 avformat_alloc_output_context2)时,我没有收到此错误,并且它成功地写入了标头。我试图分析这个例子的代码, 但我无法弄清楚问题是什么(我也尝试了不同的函数但没有结果)。
这是我的代码:
const char *filename = "c:\\Users\\MPM\\Desktop\\test.mkv";
AVFormatContext *mkvVideo = NULL;
int ret = 0;
ret = avformat_alloc_output_context2(&mkvVideo, av_guess_format("matroska", "c:\\Users\\MPM\\Desktop\\test.mkv", NULL), "mkv", filename);
std::cout << "\n avformat_alloc_output_context2: " << ret<<"\n";
AVStream* video_stream = avformat_new_stream(mkvVideo, NULL);
video_stream->time_base.den = 25;
video_stream->time_base.num = 1;
video_stream->id = mkvVideo->nb_streams - 1;
video_stream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
video_stream->codecpar->codec_id = AV_CODEC_ID_H264;
video_stream->codecpar->bit_rate = 40000;
video_stream->codecpar->width = 1920;
video_stream->codecpar->height = 1080; …Run Code Online (Sandbox Code Playgroud)