c++ - 对于自定义 FFmpeg I/O API:关于 avio_alloc_context() 的 write_packet 回调函数的数据不正确
问题描述
我想问一个关于ffmpeg custom I/O api的问题。
问题描述:我用FFmpeg官方例子-remuxing.c测试了一个简单的转换包操作。(test1.ts -> test1.mp4)。这个操作结果是正常的。但是当我使用自定义 I/O
avio_alloc_context(buf, 65535, 1, nullptr, nullptr, write_cb, seek);
函数,自定义I/O输出写入内存,然后从这个内存写入mp4文件。发现输出文件数据与 Internal file Protocol write 不同。VLC 和 MediaInfo 无法探测它。
我使用Beyond Compare4来比较文件数据:
这张图左边是我自定义的I/O输出,右边是官方的例子(根据文件URLProtocol来输出)
我测试了很多次,每次数据大小、数据位置、数据内容都在同一个地方。当我将左边有差异的几个字节的数据更改为右边的数据时,VLC可以正常播放。
是我的操作不当,还是其他问题?
源代码:
extern "C"{
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
}
#include <unistd.h>
#include <cstdio>
#include <fcntl.h>
void process_error(int ret, const char* info)
{
if( ret < 0)
{
fprintf(stderr, info);
std::exit(-1);
}
}
int fd;
int write_packet(void *opaque, uint8_t *buf, int buf_size)
{
int ret;
ret = write(fd, buf, buf_size);
printf("write bytes %d\n", ret);
return (ret == -1) ? AVERROR(errno) : ret;
}
int64_t seek(void *opaque, int64_t offset, int whence)
{
return offset;
}
int main()
{
fd = open("/home/oaho/Desktop/22.mp4", O_CREAT | O_WRONLY, 0777);
if ( fd < 0)
{
return -1;
}
AVFormatContext *inputContext = nullptr;
AVFormatContext *ouputContext = nullptr;
int ret = avformat_open_input(&inputContext, "/home/oaho/Desktop/test1.ts", nullptr, nullptr);
process_error(ret, "could'not open input\n");
ret = avformat_find_stream_info(inputContext, nullptr);
process_error(ret, "could'not find stream information\n");
avformat_alloc_output_context2(&ouputContext, nullptr, "mp4", nullptr);
if( ouputContext == nullptr)
process_error(-1, "could'not alloc outputContext\n");
if( ouputContext->oformat==nullptr)
{
ouputContext->oformat = av_guess_format("mp4", nullptr, nullptr);
}
uint8_t* buf = nullptr;
buf = (uint8_t*)av_malloc(200 * 1024);
if( buf == nullptr)
{
return -1;
}
ouputContext->pb = nullptr;
ouputContext->pb = avio_alloc_context(buf, 200 * 1024, 1, nullptr, nullptr, write_packet, seek);
if( ouputContext->pb == nullptr)
{
return -1;
}
ouputContext->flags = AVFMT_FLAG_CUSTOM_IO;
//pre the stream avalible
int *arr = new int[inputContext->nb_streams];
if( arr == nullptr )
process_error(-1, "can't alloc array\n");
int stream_index = 0;
//get stream : video stream , audio stream , subtitle stream
for(int i = 0;i < inputContext->nb_streams;i++)
{
//get the single stream
AVStream *stream = inputContext->streams[i];
AVStream *outStream = nullptr;
AVCodecParameters *codec = stream->codecpar;
if( codec -> codec_type != AVMediaType::AVMEDIA_TYPE_VIDEO
&& codec -> codec_type != AVMediaType::AVMEDIA_TYPE_AUDIO
&& codec -> codec_type != AVMediaType::AVMEDIA_TYPE_SUBTITLE)
{
arr[i] = -1;
continue;
}
arr[i] = stream_index++;
outStream = avformat_new_stream(ouputContext, nullptr);
if(outStream == nullptr)
goto end;
int ret = avcodec_parameters_copy(outStream->codecpar, stream->codecpar);
if( ret < 0)
goto end;
//not include additional information
outStream->codecpar->codec_tag = 0;
}
ret = avformat_write_header(ouputContext, nullptr);
process_error(ret, "can't write header\n");
while(1)
{
AVPacket pkt;
av_init_packet(&pkt);
AVStream *in_stream, *out_stream;
ret = av_read_frame(inputContext, &pkt);
if( ret < 0)
break;
in_stream = inputContext->streams[pkt.stream_index];
if (arr[pkt.stream_index] < 0) {
av_packet_unref(&pkt);
continue;
}
pkt.stream_index = arr[pkt.stream_index];
out_stream = ouputContext->streams[pkt.stream_index];
/* copy packet */
pkt.pts = av_rescale_q(pkt.pts, in_stream->time_base, out_stream->time_base);
pkt.dts = av_rescale_q(pkt.dts, in_stream->time_base, out_stream->time_base);
pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
pkt.pos = -1;
//log_packet(ofmt_ctx, &pkt, "out");
ret = av_interleaved_write_frame(ouputContext, &pkt);
if (ret < 0) {
fprintf(stderr, "Error muxing packet\n");
break;
}
av_packet_unref(&pkt);
}
av_write_trailer(ouputContext);
end:
close(fd);
delete [] arr;
avformat_free_context(inputContext);
avformat_free_context(ouputContext);
return 0;
}
解决方案
推荐阅读
- linux - 无法打开 /dev/tty(2,3,4)。没有这样的文件或目录
- sed - 命令 `sed -i "s/^ \+//g; s/ \+/\t/g" 是什么意思?
- sql - 查询:查找已使用最大零件数的项目名称
- docker - docker 容器在入口点退出
- autocomplete - Angular 6 Material Autocomplete 选择错误
- c# - 如何根据循环变量动态生成嵌套循环
- c# - 何时使用 Action Delegate 而不是 Predicate Delegate
- php - 如何在客户端获取 php 函数输出?
- c - 无法在 C 中释放内存 - 动态结构和数组
- python - 无法从下拉菜单中选择值