使用 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 在我制作的这个函数中是一个**,因此为什么将元数据字典引用为&amp;(*ofmt_ctx)-&gt;metadata

【讨论】:

以上是关于使用 ffmpeg 创建一个 44 字节的标头的主要内容,如果未能解决你的问题,请参考以下文章

如何在ffmpeg中使用字节而不是文件路径?

如何通过使用 ByteBuffer 查看标头偏移量来制作字节数组?

java.io.IOException:写入“”字节的请求超出了“条目”的“字节”标头中的大小

问题:FFMPEG 使用字节位置使用 av_seek_frame 搜索

如何使用标头字节确定图像的编码

jpeg 标头的字节数组