使用 ffmpeg 创建一个 44 字节的标头
Posted
技术标签:
【中文标题】使用 ffmpeg 创建一个 44 字节的标头【英文标题】:Create a 44-byte header with ffmpeg 【发布时间】:2015-07-12 18:34:47 【问题描述】:我使用 ffmpeg 库制作了一个程序,将音频文件转换为 wav 文件。除了唯一的问题是它没有创建一个 44 字节的标头。将文件输入到 Kaldi 语音识别中时,会产生错误:
ERROR (online2-wav-nnet2-latgen-faster:Read4ByteTag():wave-reader.cc:74) WaveData: expected 4-byte chunk-name, got read errror
我通过 shntool 运行了该文件,它报告了一个 78 字节的标头。无论如何我可以使用 ffmpeg 库获得标准的 44 字节标头吗?
【问题讨论】:
能否使用 hexdup 或相关工具显示当前标题内容?我猜它有元数据或扩展波形描述(使用十六进制而不是 2 字节音频标识符),但很难确定(ext hex 默认情况下应该关闭,元数据非常典型,所以我不知道为什么你的软件会抱怨)。 我知道我会看看。我在想我只是制作自己的标题,让 ffmpeg 仍然进行转码。我应该使用 fwrite 还是其他函数来创建标题? 是的,看起来 ffmpeg 插入了一些元数据,导致标头大于 44 字节。如果只有一种方法可以防止这种情况发生。 你能用 hexdump 把标题放到你的帖子里吗?如果我能看到它插入了什么类型的元数据,就更容易就如何摆脱它提出建议(有不止一种可能性......)。 其实我刚刚摆脱了它。 FFmpeg 插入了一些关于编码器的元数据,所以我使用 av_dict_set 然后将其传递到 avformat_write_header,现在它是 44 字节。但这是之前的十六进制转储:52 49 46 46 06 90 00 00 57 41 56 45 66 6d 74 20 |RIFF....WAVEfmt | 10 00 00 00 01 00 01 00 40 1f 00 00 80 3e 00 00 |........@....>..| 02 00 10 00 4c 49 53 54 1a 00 00 00 49 4e 46 4f |....列表....信息| 49 53 46 54 0e 00 00 00 4c 61 76 66 35 36 2e 33 |ISFT....Lavf56.3| 36 2e 31 30 30 00 64 61 74 61 c0 8f 00 00 00 00 |6.100.data......| 【参考方案1】:FFmpeg 将一些关于编码器的元数据插入到头文件中。这是修复前标头的 hexdump:
00000000 52 49 46 46 06 90 00 00 57 41 56 45 66 6d 74 20 |RIFF....WAVEfmt |
00000010 10 00 00 00 01 00 01 00 40 1f 00 00 80 3e 00 00 |........@....>..|
00000020 02 00 10 00 4c 49 53 54 1a 00 00 00 49 4e 46 4f |....LIST....INFO|
00000030 49 53 46 54 0e 00 00 00 4c 61 76 66 35 36 2e 33 |ISFT....Lavf56.3|
00000040 36 2e 31 30 30 00 64 61 74 61 c0 8f 00 00 00 00 |6.100.data......|
如您所见,Lavf56.36.100 是标头中的编码器。这是我用来摆脱它的代码部分。
std::cout<<"------------------BEFORE-----------------------"<<std::endl;
std::cout<< av_dict_count ( (*ofmt_ctx)->metadata) <<std::endl;
std::cout<<"-------------------------------------------"<<std::endl;
if(av_dict_set(&(*ofmt_ctx)->metadata,"ISFT",NULL, AV_DICT_IGNORE_SUFFIX))
std::cerr<<"Nope it, didn't work :("<<std::endl;
ret = avformat_write_header(*ofmt_ctx,&(*ofmt_ctx)->metadata );
if (ret < 0)
std::cout<<"-------------------------------------------"<<std::endl;
av_log(NULL, AV_LOG_ERROR, "Error occurred when writing header to file\n");
return ret;
std::cout<<"------------------AFTER-----------------------"<<std::endl;
std::cout<< av_dict_count ( (*ofmt_ctx)->metadata) <<std::endl;
std::cout<<"-------------------------------------------"<<std::endl;
这是之后的十六进制转储:
00000000 52 49 46 46 e4 8f 00 00 57 41 56 45 66 6d 74 20 |RIFF....WAVEfmt |
00000010 10 00 00 00 01 00 01 00 40 1f 00 00 80 3e 00 00 |........@....>..|
00000020 02 00 10 00 64 61 74 61 c0 8f 00 00 00 00 00 00 |....data........|
00000030 00 00 00 00 00 00 00 00 ff ff 00 00 00 00 00 00 |................|
shntool 现在报告 44 字节
(注意:ofmt_ctx 在我制作的这个函数中是一个**,因此为什么将元数据字典引用为&(*ofmt_ctx)->metadata
)
【讨论】:
以上是关于使用 ffmpeg 创建一个 44 字节的标头的主要内容,如果未能解决你的问题,请参考以下文章
如何通过使用 ByteBuffer 查看标头偏移量来制作字节数组?
java.io.IOException:写入“”字节的请求超出了“条目”的“字节”标头中的大小