Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

不进行 seek ,从头播放 1 秒左右的噪音 #39

Closed
pzhlkj6612 opened this issue Nov 12, 2019 · 3 comments
Closed

不进行 seek ,从头播放 1 秒左右的噪音 #39

pzhlkj6612 opened this issue Nov 12, 2019 · 3 comments
Labels
bug Something isn't working _Refactor the player 整个播放逻辑需要重做。

Comments

@pzhlkj6612
Copy link
Member

pzhlkj6612 commented Nov 12, 2019

这个问题可能作者也有研究过,但是到目前似乎还没有完全被解决。
我把我的发现放在这里,给以后(重新写代码时)做参考。


环境:

  • FFmpeg 4.2.1 on Windows 10 1903 / Ubuntu 18.04 / macOS 10.14
  • FFmpeg 4.0.1 on Windows 10 1903

我把刚测试出来的一个“解决方法”写在这里,稍后会补充探究过程。

PlayThread::initDeviceAndFfmpegContext()方法中,移除整个关于AVFormatContext->iformat->read_header(struct AVFormatContext *)的代码:

https://github.com/Beslyric-for-X/Beslyric-for-X/blob/0dee64a8834f1ba294b12f99fee97acc438ee500/Entities/MusicPlayer/musicPlayer.cpp#L391-L396

接着把PlayThread::generateAudioDataLoop()方法中的seekToPos(10)注释掉,然后运行程序,播放音乐,开头的噪音应该就会消失了。


然而我并不知道这背后的原理……

@pzhlkj6612
Copy link
Member Author

pzhlkj6612 commented Nov 13, 2019

以下是可能没啥用的流水账。


在 Ubuntu 和 macOS 上,不进行开头的 seek 直接播放,当噪音出现时,我注意到 Application Output 输出了一行或多行的[mp3float @ 0x012345abcdef] Header missing
网上有类似的问题,例如mp3 decoding using ffmpeg API (Header missing) - Stack Overflow,但我不知如何入手。

由于av_dump_format()的存在,从头播放一首音乐时, Application Output 会输出大量关于当前音频文件的信息(使我不太能注意到另外一些特别的信息),于是将这个调用注释,再次播放音乐。接着我注意到了以下内容:

...
"disc" : "1"
"track" : "3"
[mp3 @ 0x7fffac0352c0] Skipping 41 bytes of junk at 563945.
...

我不明白这意味着什么,因为之前(在 Ubuntu 上开发时)见到过许多次了,有时还会同时出现Skipping 0 bytes of junk at NNNNNN.
我回过头继续搜索Header missing的资料,然后看到了FFMPEG 解码MP3的Header Missing报错-CSDN论坛。提问者提供了一个关键信息:

...
//avcodec_decode_audio4返回无效值,得到错误信息为Header Missing
if ((ret = avcodec_decode_audio4(in_fmtctx->streams[audiostream_index]->codec, frame, &got_frame, &packet)) < 0)
{
        av_free_packet(&packet);
        av_frame_free(&frame);
        return 0;
}
...

Beslyric-for-X 也使用的avcodec_decode_audio4(),于是尝试输出它的返回值:

  decodeLen = avcodec_decode_audio4(MS->acct, pframe, &got_frame, &packet);
  if (decodeLen < 0) // 出错,跳过
+ {
+     qDebug()<<decodeLen;
      break;
+ }

当噪音出现时:

...
[mp3float @ 0x7fffac035900] Header missing
-1094995529
...

windows - ffmpeg exit status -1094995529 - Stack Overflow可知,“-1094995529”是AVERROR_INVALIDDATA,表示“Invalid data found when processing input”。
将断点下在avcodec_decode_audio4() < 0条件满足处,播放音乐,命中断点。查看packet(即从队列中取出的包)的属性:

Name Value Type
buf @0x7fffac044380 AVBufferRef
convergence_duration 0 int64_t
data 235 uint8_t
dts 18800640 int64_t
duration 368640 int64_t
flags 1 int
pos 563986 int64_t
pts 18800640 int64_t
side_data 0x0 AVPacketSideData*
side_data_elems 0 int
size 2049 int
stream_index 0 int

此处AVPacket.pos的值(563986)等于Skipping 41 bytes of junk at 563945.中的两数之和。

“似乎发现了什么?”


接着,我尝试在PlayThread::generateAudioDataLoop()方法中的while(!g_isQuit)循环头部输出PacketQueue队头的包的信息(省略掉了一些暂时用不到的属性),以及当前的毫秒时间m_MS.audio_clock

if(m_MS.audioq.first_pkt != nullptr){
    auto plist = m_MS.audioq.first_pkt;

    auto buf = plist->pkt.buf;
    auto data = plist->pkt.data;
    auto size = plist->pkt.size;
    auto pos = plist->pkt.pos;

    qDebug()<<"{";
    qDebug()<<"\tpkt.buf"<<buf;
    qDebug()<<"\tpkt.data[0]"<<data[0];
    qDebug()<<"\tpkt.size"<<size;
    qDebug()<<"\tpkt.pos"<<pos;
    qDebug()<<"}";

    qDebug()<<m_MS.audio_clock;
}

输出:

{
	pkt.buf 0x7f76340120c0
	pkt.data[0] 255
	pkt.size 1045
	pkt.pos 562941
}
1280
{                                            <- 注意,从这里开始
	pkt.buf 0x7f76342a7e00
	pkt.data[0] 235
	pkt.size 2049
	pkt.pos 563986
}
1306
{
	pkt.buf 0x7f76342a7e00
	pkt.data[0] 235
	pkt.size 2049
	pkt.pos 563986
}
1306
[mp3float @ 0x7f76340049c0] Header missing   <- Boom!
-1094995529                                  <- Boom!!
{
	pkt.buf 0x7f7634015c00
	pkt.data[0] 255
	pkt.size 1045
	pkt.pos 567080
}
1358

我测试了其它的歌曲,发现在出现噪音时:

  • 都是在第 1306 毫秒处出现Header missing(这也符合 Beslyric-for-X 作者的观察);
  • pkt.data[0]可能不为 255 (我这边 4 首歌,有 1 首仍然是 255 );
  • pkt.size不为 1045 ,我目前见到的有 1462 和 2049 (其它的包暂时没发现不为 1045 的);
  • pkt.pos一定等于开始播放时Skipping MM bytes of junk at NNNNNN.中的两数之和。

到这里,我就进行不下去了,因为实在不懂 FFmpeg 这些。

我把注意力回到从头播放一首音乐时输出的Skipping MM bytes of junk at NNNNNN.上。在PlayThread::initDeviceAndFfmpegContext()内单步调试,注意到这个判断:

//读取音频的专辑图片
// read the format headers
if (pFormatCtx->iformat->read_header(pFormatCtx) < 0) {
    printf("No header format");
    //return;
}

它被执行后,输出了Skipping MM bytes of junk at NNNNNN.。注释掉这一块代码,播放音乐,噪音没了,上述的有关输出都消失了。


问题暂时“解决”。

@pzhlkj6612
Copy link
Member Author

这里有一个比较坑的地方,不过不确定是不是我自己的问题。

虽然在各个平台上av_log_get_level()都返回 32 ,即AV_LOG_INFO(这应该是个默认值),但是我这边的 Windows 却没有像 Ubuntu 、 macOS 那样输出Skipping MM bytes of junk at NNNNNN.Header missing。直到设置av_log_set_level(AV_LOG_DEBUG)及以上(AV_LOG_DEBUG为 48),才能看到这些比较关键的信息。

我 Windows 上用的 MSVC2015 32bit ,Ubuntu 和 macOS 都是用的 GCC x86_64 ,不知道跟这个有无关系。


另外,我这边 Windows 上 Application Output 的输出似乎没有 Ubuntu 上的那么流畅,体验稍差。就开发 Beslyric-for-X 来说, Linux 环境可能是个好选择。

@BensonLaur
Copy link
Member

试了一下,windows 下确实是加上 av_log_set_level(AV_LOG_DEBUG) 才看到了Header missing信息

@pzhlkj6612 pzhlkj6612 added bug Something isn't working _Refactor the player 整个播放逻辑需要重做。 labels Feb 23, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working _Refactor the player 整个播放逻辑需要重做。
Projects
None yet
Development

No branches or pull requests

2 participants