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

Corrupt decoding :( #24

Closed
Paul-Arnold opened this issue Feb 15, 2022 · 14 comments
Closed

Corrupt decoding :( #24

Paul-Arnold opened this issue Feb 15, 2022 · 14 comments

Comments

@Paul-Arnold
Copy link

Paul-Arnold commented Feb 15, 2022

Hi,
I was looking forward to using this in a m.a.m.e. project but for some reason it doesn't correctly decode the mpg files I've got.
The files are OK, they play with vlc and all other players I've tried including a hardware decoder :(
The decoded data is wrong from frame one :(
I've absolutely no idea how to fault finding on this :(
I've many files all with similar problems. This is the first frame from a file here.
https://drive.google.com/file/d/1_wrjTUzgTOf9hCEqX-G6tlmaoBSp1I2_/view?usp=sharing
000001

Anyone any suggestions or ideas ? Any help is really appreciated.
Thanks
Paul

@Zero3K
Copy link

Zero3K commented Feb 17, 2022

MAME? Is that the arcade emulator?

@Paul-Arnold
Copy link
Author

Paul-Arnold commented Feb 17, 2022 via email

@jrdennisoss
Copy link
Contributor

I actually fixed this problem in the fork of PL_MPEG I am using for the DOSBox ReelMagic project. Here is the change I made: jrdennisoss/dosboxrm@712f309

What is happening is that sometimes a slice boundary is blown through because the ISO spec allows for a bit of extra '0' padding at the end, but the current version of PL_MPEG is not quite handling this right. I made a patch which guards the slice boundary based on the known last macroblock address for that specific slice. I tested with your MPG file you posted above and this seems to do the trick.

@jrdennisoss
Copy link
Contributor

I created a pull request which should fix this: #26

This awesome library has proved to be invaluable to the project I have been working on, I figure contributing something back is the very least I should do 😄

@Paul-Arnold
Copy link
Author

That’s brilliant, thanks for reporting the fix.
I started to look but my lack of knowledge on mpeg and trying to understand how it should work meant I quickly got lost :(
Unfortunately I switched to another library for my current project but will investigate the use of this one again to see if it’s worth trying to switch back.

Thanks again
Paul

@Paul-Arnold
Copy link
Author

For further info, I've just tested this update using 30+ mpeg files which previously suffered massive amounts of corruption and they all decode correctly :)

@livid123
Copy link

but this patch not working on bjork-all-is-full-of-love.mpg

@jrdennisoss
Copy link
Contributor

Oh crap... Good catch @livid123 I'll close the pull request I opened until I fully understand this... Probably need to implement something that truly finds the slice boundary instead of assuming that there is only one macroblock row per slice.

@Paul-Arnold
Copy link
Author

Paul-Arnold commented Mar 13, 2022

I've looked at what my working decoder does and it continues processing macro blocks until the next 23 bits are 0.
Ie, it doesn't abort on finding a start code but on a possible start code. It doesn't check if the 23 bits are aligned.
A quick test changing plm_buffer_no_start_code() to the following and it appears to work on bjork and my files.
Can someone confirm it works on others too ?

int plm_buffer_no_start_code(plm_buffer_t *self) {
int code;
if (!plm_buffer_has(self, (23))) {
return FALSE;
}

code = plm_buffer_read(self, 23);

self->bit_index -= 23;//rewind buffer pointer as we're only peeking

return code != 0 ;

}

Edit: In addition to the above the macro processing loop can become as follows
do {
plm_video_decode_macroblock(self);
} while ( plm_buffer_no_start_code(self->buffer) );

@jrdennisoss
Copy link
Contributor

I FINALLY had a few cycles to take a look at this over lunch today... THANK YOU Paul for a MUCH more in-spec solution than the hack I earlier suggested... Yes I confirm this works on my setup and actually fixes another issues I had too! 😄

I ended up deviating slightly from what you had:

int plm_buffer_peek_non_zero(plm_buffer_t *self, int bit_count) {
    if (!plm_buffer_has(self, bit_count)) {
        return FALSE;
    }

    int val = plm_buffer_read(self, bit_count);
    self->bit_index -= bit_count;
    return val != 0;
}
void plm_video_decode_slice(plm_video_t *self, int slice) {
    self->slice_begin = TRUE;
    self->macroblock_address = (slice - 1) * self->mb_width - 1;

    // Reset motion vectors and DC predictors
    self->motion_backward.h = self->motion_forward.h = 0;
    self->motion_backward.v = self->motion_forward.v = 0;
    self->dc_predictor[0] = 128;
    self->dc_predictor[1] = 128;
    self->dc_predictor[2] = 128;

    self->quantizer_scale = plm_buffer_read(self->buffer, 5);

    // Skip extra
    while (plm_buffer_read(self->buffer, 1)) {
        plm_buffer_skip(self->buffer, 8);
    }

    do {
        plm_video_decode_macroblock(self);
    } while (
        self->macroblock_address < self->mb_size - 1 &&
        plm_buffer_peek_non_zero(self->buffer, 23)
    );
}

The logic is exactly the same as yours, but I renamed things to better match what ISO/IEC 11172-2 says as its logic is pretty explicit: do ... while the next 23 bits are not zero. Then only after the do/while condition is the start code checked.

@Zero3K
Copy link

Zero3K commented Mar 17, 2022

Will you make a new PR soon since you have now fixed the issues that @livid123 and you have found?

@jrdennisoss
Copy link
Contributor

Sure thing: #28

@Paul-Arnold
Copy link
Author

Thanks for doing the nicer named solution Jon. Great that it fixes your other issue too.

I simply compared your original solution with the decoder I'm using (which is based on the early Berkeley code), doubt I'd have found it otherwise.

@phoboslab
Copy link
Owner

Outstanding work everyone! Thank you so much :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants