Opened 9 years ago

Closed 6 years ago

#12436 closed bug (fixed)

BMediaTrack()::ReadFrames() polluted after Seeking MP3

Reported by: ttcoder Owned by: nobody
Priority: high Milestone: R1/beta1
Component: Audio & Video/Codecs Version: R1/Development
Keywords: Cc:
Blocked By: Blocking:
Platform: x86

Description

See attached sample. Here's an outline of what it does:

Steps:

  • ReadFrames()
  • dump bytes
  • SeekToTime( time 0 ) (SeekToFrame() also triggers the bug)
  • ReadFrames()
  • dump bytes : they are badly corrupted ! (not at all like those returned by a "fresh" BMediaTrack)

It seems the 'corruption' is not quite random, the buffer seems to be filled with average values (old buffer + new buffer / 2). For instance if you read only one buffer's worth of data (instead of 22 as in my sample) and the data is 0x0 through and through, doing a Seek and then ReadFrames() again will still return a buffer filled with 0x0's as it should. But if you went farther along in the audio file and your last read buffer had high volume samples, seeking back to the (silent) beginning of the file will no longer yield 0x0s but medium'ish samples instead.

Workaround 1 is to discard the BMediaFile object and re-instantiate it before seeking (too expensive).

Workaround 2 is to keep the BMediaFile and BMediaTrack, but throw away the contents returned by the first 2 ReadFrames() calls as it seems they are the only ones "polluted".... Not a great solution, would love to see ReadFrames() be fixed to start with :-)

Attachments (1)

BMediaTrack-weirdness.cpp (1.4 KB ) - added by ttcoder 9 years ago.
Tweak, compile, run and observe buffer contents

Download all attachments as: .zip

Change History (13)

by ttcoder, 9 years ago

Attachment: BMediaTrack-weirdness.cpp added

Tweak, compile, run and observe buffer contents

comment:1 by Barrett, 9 years ago

I don't think this is directly related to the media_kit but most probably to the decoder. Anyway this may explain some crashes that may incur playing some files with the MediaPlayer.

comment:2 by pulkomandy, 9 years ago

It is easy to test this: does it happen also on APE file (Monkey's Audio)? These are handled by another decoder (not ffmpeg based), if the problem doesn't happen there, it means it is the ffmpeg decoder fault.

The main difficulty is finding an APE file for testing, but there is at least one here: http://samples.mplayerhq.hu/A-codecs/lossless/

comment:3 by ttcoder, 9 years ago

Seems I selected the wrong component indeed, it should be the mp3 codec instead. Details:

  • first tried the APE file here but playback is completely silent. Haiku does have a /system/add-ons/media/plugins/ape_reader add-on but I'm not sure it's used, seems ffmpeg is used instead for reading APE audio (the output is the same if using MediaPlayer):
Compiler did not align stack variables. Libavcodec has been miscompiled
and may be very slow or crash. This is not a bug in libavcodec,
but in the compiler. You may try recompiling using gcc >= 4.2.
Do not report crashes to FFmpeg developers.
########### audio decode error, fTempPacket.size 0, fChunkBuffer data offset 0
...
BMediaTrack::ReadFrames: decoder returned error 0x80004007 (Last buffer)
...
BMediaTrack::ReadFrames: decoder returned error 0x80000000 (Out of memory)
...
  • then I tried luckynight.flac and Seek'ing works normally there.
  • then I tried luckynight.wav and it also seems to work normally
  • if going back to an mp3 however, the bug is back.

Maybe the mpeg layer 3 algorithm uses some sort of "rolling average" or psycho-accoustic machine state that ought to be reset (but is currently not) when Seek'ing, or something like that ?

Last edited 9 years ago by ttcoder (previous) (diff)

comment:4 by pulkomandy, 9 years ago

Component: Kits/Media KitAudio & Video/Codecs
Owner: changed from Barrett to nobody
Summary: BMediaTrack()::ReadFrames() polluted after SeekingBMediaTrack()::ReadFrames() polluted after Seeking MP3

The APE reader is supposed to have higher priority for APE files, it's surprising that this doesn't work. I will have a look if we can do something with MP3 to clear the context.

comment:5 by Barrett, 9 years ago

Both flac and wav are lossless audio format, so they should be (at least at low level) perfectly seekable. Mp3 is not perfectly seekable, then the intuition suggest that this is the problem probably. I would be not surprised if with ogg the result is similar, but as said this is a guess so i may have hit the target or be out of road at the same time :-)

I think there may be an error which over a certain size of the seek is accumulated and produce wrong frames, at least the crashes that i was talking doesn't happens for little seeks. Also the ape plugin priority should be investigated.

comment:6 by pulkomandy, 9 years ago

IIRC, stippi implemented seeking so we go back to a keyframe before the seek point, and decode from there to the seek point and drop the frames. This provides perfect seeking even for lossy formats (it is done in the ffmpeg add-on).

comment:7 by ttcoder, 9 years ago

The bigtime_t argument of Seek..(bigtime_t * seekto) is indeed often modified in my testing, so that could be a factor in this whole equation. But IMHO this whole thing is a bug, not a 'feature', as imperfect seeking justifies sending another buffer than the one at the request time, but cannot justify sending some random buffer data that does not exist in the file :-) .. Also I have noticed that I can reproduce the bug also when seeking is 'perfect', that is to say -- SeekToTime(0) tends to seek perfectly to 0, yet the buffer data is corrupted.

Also I've just modified the test case to use all 3 scenarios (no flags, track->SeekToTime( &time, B_MEDIA_SEEK_CLOSEST_BACKWARD ), track->SeekToTime( &time, B_MEDIA_SEEK_CLOSEST_FORWARD )) and it makes no difference..

Anyway I'll wait for you guys to take a look when time permits (I know the ffmpeg add-on is a bit hairy); I'll just post a bit of testing data I get here as a motivational post :-).. That song I test with exhibits the problem very well:

Frames for CurrentTime 0:
 
0000000000000000 0000000000000000 0000000000000000 0000000000000000 
0000000000000000 0000000000000000 0000000000000000 0000000000000000 
0000000000000000 0000000000000000 0000000000000000 0000000000000000 
0000000000000000 0000000000000000 0000000000000000 0000000000000000
(...)

Frames for CurrentTime 11609:
 
0000000000000000 0000000000000000 0000000000000000 0000000000000000 
0000000000000000 0000000000000000 0000000000000000 0000000000000000 
0000000000000000 0000000000000000 0000000000000000 0000000000000000 
0000000000000000 0000000000000000 0000000000000000 0000000000000000
(...)

=============================== calling SeekToTime(0) (status 0x0) =============


Frames for CurrentTime 0:
 
0000000000000000 0000000000000000 0000000000000000 0000000000000000 
0000000000000000 000000000000ffff 0000000000000000 0000000000000000 
0000000000000000 0000000000000000 0000000000000100 0000010001000000 
00000000ffff0000 000000000000ffff 00000000ffff0000 0000000000000000
(...)

Frames for CurrentTime 11609:
 
9af86efd0df7cafc e1f51ffc5ef5e3fb 63f5e3fbd2f520fc c1f6a3fcf2f726fd 
80f9d2fd21fb4efe 9dfcd4fefcfd37ff f7fe48ffa9ff70ff ebff5eff9cff4aff 
dbfe30ffc2fdf5fe 76fcd2fe26fb7ffe 1afa44fe3bf9fefd b7f8a1fda3f899fd 
f1f897fdd6f9d0fd 08fb3ffe85fcd6fe 38fea4fff0ff6200 bb013a013803c701
(...)

Frames for CurrentTime 23218:
 
0000000000000000 0000000000000000 0000000000000000 0000000000000000 
0000000000000000 0000000000000000 0000000000000000 0000000000000000 
0000000000000000 0000000000000000 0000000000000000 0000000000000000 
0000000000000000 0000000000000000 0000000000000000 0000000000000000
(...)

comment:8 by Barrett, 9 years ago

I've tested your sample code but i've a slightly different behavior. When j is equal to count the CurrentTime() doesn't reset to zero and i just continue to get data.

comment:9 by ttcoder, 9 years ago

That's an interesting/important bug Barrett.. I think I remember Seek failures in an hrev last year on FLAC audio, but didn't experience such failures since.. What file format/codec do you use to reproduce this behavior, what is the status_t return code ?

comment:10 by pulkomandy, 8 years ago

Platform: Allx86

I tried several files. There are some errors with MP3, and complete garbage with ogg (more than 50% of the bytes are different each time).

However, I also tried a gcc5 build of the same test app, and there I found no problems at all. This hints further to a problem in ffmpeg, rather than in the Media Kit.

@ttcoder: I suggest building your apps with gcc5, if possible, to get the new ffmpeg version.

comment:11 by waddlesplash, 6 years ago

Confirmed that https://github.com/haikuports/haikuports/pull/2758 fixes this issue for GCC2.

comment:12 by waddlesplash, 6 years ago

Resolution: fixed
Status: newclosed

Fixed in hrev52057.

Note: See TracTickets for help on using tickets.