omf
3rd December 2007, 20:35
I recently wanted to play some AVC Level 5.1 videos in MKV containers on my PS3. Searching through some of the recent threads on here gave me all the information I needed, and I was able to play the files perfectly.
Since the needed information is still a bit spread-out, I thought I'd summarize the steps I needed, both for the benefit of others looking to do the same thing and to see if anyone had any improvements to add to the process.
ASSUMPTIONS
1. I've tested this procedure with a few dozen MKV files, but they were all in the same format:Video stream: H.264/MPEG-4 AVC (x264)
(High Profile, Level 5.1)
960x720 23.98fps @ 3468Kbps
Audio stream: AC3
5.1 (6 channels) 48KHz @ 640Kbps
There is useful information here applicable to other formats, however.
2. My target was a Playstation 3 running version 2.01
3. I did not want to re-encoded the video
4. Audio was not as important: it may or may not be re-encoded (see below)
5. I get wordy in my explanations, so I hope you don't mind a little reading...
INFORMATION SOURCES
Here are some of the key forum threads that helped me put the process together:
http://forum.doom9.org/showthread.php?t=120627
http://forum.doom9.org/showthread.php?t=131782
http://www.redkawa.com/forums/showthread.php?t=1906
TOOLS
MKVINFO and MKVEXTRACT from the MKVToolnix package
http://www.bunkus.org/videotools/mkvtoolnix/
Depending on which method you choose, you'll need some of these:
H264Info
http://sourceforge.net/projects/batchccews/
FFMPEG included in MPlayer
http://www.mplayerhq.hu/
MP4BOX from the GPAC package
http://gpac.sourceforge.net/
Nero AAC Encoder (NEROAACENC)
http://www.nero.com/enu/nero-aac-codec.html
EAC3TO
http://forum.doom9.org/showthread.php?t=125966
http://madshi.net/eac3to.zip
PROCEDURE SUMMARY
Here are the steps. Look at PROCEDURE DETAIL if you want to know more.
1. Determine MKV Source Streams
This tells you which MKV track is video and which is audio, and the video frame rate:
mkvinfo.exe sourcefile.mkv
2. Demux MKV Source File
Assuming track 1 is video and track 2 is audio:
mkvextract tracks sourcefile.mkv 1:video.h264 2:audio.ac3
3. Change Profile Level
Method A:
Use H264Info.exe from http://sourceforge.net/projects/batchccews/
Only change profile level to 4.1 (leave other fields blank) and write output to "video-changed.h264"
Continue to step 4A
Method B:
Use a hex editor to change "0167640033" to "0167640029" at the beginning of "video.h264".
Alternately, use BINREPLACE.EXE (attached here):
binreplace video.h264 0167640033 0167640029
Continue to step 4B
4A. Mux Video and Audio into VOB
Replace "23.976" with frame rate from MKVINFO in step 1:
ffmpeg.exe -r 23.976 -f h264 -i video-changed.h264 -f ac3 -i audio.ac3 -vcodec copy -acodec copy -f vob output.vob
Continue to step 7A
4B. Convert AC3 to WAV
eac3to.exe audio.ac3 audio.wav
5B. Convert WAV to AAC
neroaacenc.exe -if audio.wav -of audio.aac
6B. Mux Video and Audio into MP4
Replace "23.976" with frame rate from MKVINFO in step 1:
mp4box.exe -add video.h264 -fps 23.976 -add audio.aac -new output.mp4
7A. Transfer File to PS3
You can change the extension to MPG or M2TS if you prefer - it won't make a difference. Multi-channel audio should work (assuming your receiver or TV does multi-channel). Trying to fast-forward or rewind during playback with break audio-video synchronization. Start playback from beginning to re-synch.
7B. Transfer File to PS3
Playback should work correctly, including fast-forward and rewind, but you won't get anything other than stereo audio unless your TV or receiver supports AAC natively.
PROCEDURE DETAIL
1. Determine MKV Source Streams
You need to know which stream is audio and which is video within the MKV file. MKVINFO.EXE (from the MKVtoolnix package) will tell you this.
mkvinfo.exe sourcefile.mkv
The output will detail whether each stream (MKVINFO calls them "tracks") is audio or video. You'll need to know that for the next step. Also, note that the details for the video track tell us the frame rate. It looks something like this:
Default duration: 41.708ms (23.976 fps for a video track)
You'll need to know the FPS value later on.
2. Demux the MKV Source File
Since the PS3 doesn't presently know how to read MKV files, we'll "repackage" the audio and video streams it holds into something it does understand. We have to extract (or "demux") the streams first using MKVEXTRACT.EXE (which is also included in the MKVtoolnix package).
mkvextract tracks sourcefile.mkv 1:video.h264 2:audio.ac3
This will open the file "sourcefile.mkv" and save the first stream into a file named "video.h264" and the second stream into a file named "audio.ac3". Replace "sourcefile.mkv" with your MKV file, but keep the output file names so you can follow this procedure. (Also, I discovered "the hard way" that some utilities depend on the file extension to determine the kind of file they're working with, so "video.h264" will work, but "video.mp4" will not.)
If your video and audio tracks are not 1 and 2 respectively, then change those accordingly. For example, if MKVINFO.EXE told you that the first track is audio and the second is video, then just change the command to:
mkvextract tracks sourcefile.mkv 1:audio.ac3 2:video.h264
MKVEXTRACT.EXE should do its work very quickly and create the output files about as fast as your hard drive(s) can read and write the data.
3. Change MPEG-4 Profile Level
You can skip this step entirely if the video in your source MKV file is already below profile level 5.1. You may want to keep reading if it's profile level 4.2, though.
This step benefits from some explanation. If you're not interested in the background information, skip ahead to choose Method A or Method B.
MPEG-4 players can handle different MPEG-4 profiles and levels. Basically, the higher the profile and level, the more horsepower is required to play the file back properly. As of version 2.01, the PS3 will officially play back MPEG-4 H.264/AVC High Profile streams up to Level 4.2.
It turns-out the PS3 will actually play back Level 5.1 streams, though, if you simply trick it into thinking the stream you're playing is Level 4.2 or lower. It's quite likely it will fail to play some highly-demanding streams this way, but I haven't run into any so far.
The PS3 will only check the beginning of the MPEG-4 file to see what profile and level it is. If it sees something above its officially supported rates, you'll see the dreaded "Unsupported Format" icon in the XMB.
In my tests I found that, although the "Unsupported Format" icon went away when I changed my source files to High Profile - Level 4.2, the PS3 would show no video when I attempted to play back the file. Changing the file to High Profile - Level 4.1 resolved that problem, so that's what we're doing here.
How do we change the MPEG-4 profile level without re-encoding the video? Since we're just going to trick the PS3 into thinking it's a Level 4.1 file, all we have to do is change the bits in the stream that tell the PS3 what level it is. We have a couple of options:
Method A: H264INFO.EXE
H264INFO.EXE lets you change various settings, not just the profile level. You can obtain the program here:
http://sourceforge.net/projects/batchccews/ (as of this writing, the latest H264Info release is "Alpha 0.13").
Simply run the program, enter your source video stream, "video.h264", for the input file, "video-changed.h264" for the output file, and put 4.1 in the Level box. LEAVE EVERYTHING ELSE BLANK.
When you hit the Start button, H264INFO will read the input file and create a new packet/block (I'm not sure which is the correct terminology for this) using the updated information you gave it.
Because the program has to interpret each source packet and build each output packet, the processing can take some time. Also, you'll have to have enough disk space for both "video.h264" and "video-changed.h264", although you can delete "video.h264" as soon as this step is completed.
Continue to step 4A.
Method B: BYTE EDITING
Instead of properly updating the profile level for every packet in the video stream, we can just update the first packet. This has the advantage of being very fast and not requiring disk space for a second copy of the "video.h264" file - we can just change the right byte in "video.h264" directly.
There's a big "however" here, though: this only worked for me when using the MP4BOX.EXE method in the muxing step below. If you use this method and then mux the video and audio streams with something other than MP4BOX.EXE, you end-up with the ol' "Unsupported Format" icon on the PS3.
I suspect MP4BOX.EXE reads the profile level in the first packet and writes that same level in all other packets as it does its muxing, while other tools write the profile level information from the source stream all the way through without change. Or something like that - a little more investigative work will reveal the details.
So why not just always use MP4BOX.EXE for muxing? The reason is that MP4BOX.EXE only accepts audio in AAC or MP3 formats. If the audio in your MKV file is already in one of these formats or you don't mind converting it, then you're all set. I chose to convert the AC3 in my source file to AAC because the PS3 has an easier time playing it.
Ok, so how do you edit the correct byte?
You'll need a hex/binary editor for this (I use XVI32 - http://www.chmaas.handshake.de/delphi/freeware/xvi32/xvi32.htm - but it has the disadvantage of loading the entire file into memory, which will be a problem in many cases).
Open "video.h264" in the hex editor. Right at the beginning of the file you should see:
00 00 00 01 67 64 00 33
I don't know all the gritty details, but the "000001" should be the "start code" and "67" is the "NAL type". "640033" is what we really care about. "64" indicates "High Level". "33" is "51" in decimal, so that's "Profile Level 5.1". All we need to do is change that "33" into a "29" (which is "41" in decimal).
I wrote a little utility to change bytes like this. There are others out there, but I couldn't find one that you could ask to stop after it found and replaced the first match (you don't want it finding and replacing other "640033" further on in the file that may have nothing to do with the profile level).
Here's how you use it:
binreplace.exe video.h264 0167640033 0167640029
The string after the name of the input file is a string of hex bytes it should search for, "0167640033". We could've just said "640033" or even just "33", but the more specific we are, the less chance there is of accidentally finding and changing something that wasn't the profile level. The second string is the replacement bytes.
BINREPLACE.EXE works very quickly and can deal with files over 4GB in size.
Continue to step 4B.
Continued in next post
Since the needed information is still a bit spread-out, I thought I'd summarize the steps I needed, both for the benefit of others looking to do the same thing and to see if anyone had any improvements to add to the process.
ASSUMPTIONS
1. I've tested this procedure with a few dozen MKV files, but they were all in the same format:Video stream: H.264/MPEG-4 AVC (x264)
(High Profile, Level 5.1)
960x720 23.98fps @ 3468Kbps
Audio stream: AC3
5.1 (6 channels) 48KHz @ 640Kbps
There is useful information here applicable to other formats, however.
2. My target was a Playstation 3 running version 2.01
3. I did not want to re-encoded the video
4. Audio was not as important: it may or may not be re-encoded (see below)
5. I get wordy in my explanations, so I hope you don't mind a little reading...
INFORMATION SOURCES
Here are some of the key forum threads that helped me put the process together:
http://forum.doom9.org/showthread.php?t=120627
http://forum.doom9.org/showthread.php?t=131782
http://www.redkawa.com/forums/showthread.php?t=1906
TOOLS
MKVINFO and MKVEXTRACT from the MKVToolnix package
http://www.bunkus.org/videotools/mkvtoolnix/
Depending on which method you choose, you'll need some of these:
H264Info
http://sourceforge.net/projects/batchccews/
FFMPEG included in MPlayer
http://www.mplayerhq.hu/
MP4BOX from the GPAC package
http://gpac.sourceforge.net/
Nero AAC Encoder (NEROAACENC)
http://www.nero.com/enu/nero-aac-codec.html
EAC3TO
http://forum.doom9.org/showthread.php?t=125966
http://madshi.net/eac3to.zip
PROCEDURE SUMMARY
Here are the steps. Look at PROCEDURE DETAIL if you want to know more.
1. Determine MKV Source Streams
This tells you which MKV track is video and which is audio, and the video frame rate:
mkvinfo.exe sourcefile.mkv
2. Demux MKV Source File
Assuming track 1 is video and track 2 is audio:
mkvextract tracks sourcefile.mkv 1:video.h264 2:audio.ac3
3. Change Profile Level
Method A:
Use H264Info.exe from http://sourceforge.net/projects/batchccews/
Only change profile level to 4.1 (leave other fields blank) and write output to "video-changed.h264"
Continue to step 4A
Method B:
Use a hex editor to change "0167640033" to "0167640029" at the beginning of "video.h264".
Alternately, use BINREPLACE.EXE (attached here):
binreplace video.h264 0167640033 0167640029
Continue to step 4B
4A. Mux Video and Audio into VOB
Replace "23.976" with frame rate from MKVINFO in step 1:
ffmpeg.exe -r 23.976 -f h264 -i video-changed.h264 -f ac3 -i audio.ac3 -vcodec copy -acodec copy -f vob output.vob
Continue to step 7A
4B. Convert AC3 to WAV
eac3to.exe audio.ac3 audio.wav
5B. Convert WAV to AAC
neroaacenc.exe -if audio.wav -of audio.aac
6B. Mux Video and Audio into MP4
Replace "23.976" with frame rate from MKVINFO in step 1:
mp4box.exe -add video.h264 -fps 23.976 -add audio.aac -new output.mp4
7A. Transfer File to PS3
You can change the extension to MPG or M2TS if you prefer - it won't make a difference. Multi-channel audio should work (assuming your receiver or TV does multi-channel). Trying to fast-forward or rewind during playback with break audio-video synchronization. Start playback from beginning to re-synch.
7B. Transfer File to PS3
Playback should work correctly, including fast-forward and rewind, but you won't get anything other than stereo audio unless your TV or receiver supports AAC natively.
PROCEDURE DETAIL
1. Determine MKV Source Streams
You need to know which stream is audio and which is video within the MKV file. MKVINFO.EXE (from the MKVtoolnix package) will tell you this.
mkvinfo.exe sourcefile.mkv
The output will detail whether each stream (MKVINFO calls them "tracks") is audio or video. You'll need to know that for the next step. Also, note that the details for the video track tell us the frame rate. It looks something like this:
Default duration: 41.708ms (23.976 fps for a video track)
You'll need to know the FPS value later on.
2. Demux the MKV Source File
Since the PS3 doesn't presently know how to read MKV files, we'll "repackage" the audio and video streams it holds into something it does understand. We have to extract (or "demux") the streams first using MKVEXTRACT.EXE (which is also included in the MKVtoolnix package).
mkvextract tracks sourcefile.mkv 1:video.h264 2:audio.ac3
This will open the file "sourcefile.mkv" and save the first stream into a file named "video.h264" and the second stream into a file named "audio.ac3". Replace "sourcefile.mkv" with your MKV file, but keep the output file names so you can follow this procedure. (Also, I discovered "the hard way" that some utilities depend on the file extension to determine the kind of file they're working with, so "video.h264" will work, but "video.mp4" will not.)
If your video and audio tracks are not 1 and 2 respectively, then change those accordingly. For example, if MKVINFO.EXE told you that the first track is audio and the second is video, then just change the command to:
mkvextract tracks sourcefile.mkv 1:audio.ac3 2:video.h264
MKVEXTRACT.EXE should do its work very quickly and create the output files about as fast as your hard drive(s) can read and write the data.
3. Change MPEG-4 Profile Level
You can skip this step entirely if the video in your source MKV file is already below profile level 5.1. You may want to keep reading if it's profile level 4.2, though.
This step benefits from some explanation. If you're not interested in the background information, skip ahead to choose Method A or Method B.
MPEG-4 players can handle different MPEG-4 profiles and levels. Basically, the higher the profile and level, the more horsepower is required to play the file back properly. As of version 2.01, the PS3 will officially play back MPEG-4 H.264/AVC High Profile streams up to Level 4.2.
It turns-out the PS3 will actually play back Level 5.1 streams, though, if you simply trick it into thinking the stream you're playing is Level 4.2 or lower. It's quite likely it will fail to play some highly-demanding streams this way, but I haven't run into any so far.
The PS3 will only check the beginning of the MPEG-4 file to see what profile and level it is. If it sees something above its officially supported rates, you'll see the dreaded "Unsupported Format" icon in the XMB.
In my tests I found that, although the "Unsupported Format" icon went away when I changed my source files to High Profile - Level 4.2, the PS3 would show no video when I attempted to play back the file. Changing the file to High Profile - Level 4.1 resolved that problem, so that's what we're doing here.
How do we change the MPEG-4 profile level without re-encoding the video? Since we're just going to trick the PS3 into thinking it's a Level 4.1 file, all we have to do is change the bits in the stream that tell the PS3 what level it is. We have a couple of options:
Method A: H264INFO.EXE
H264INFO.EXE lets you change various settings, not just the profile level. You can obtain the program here:
http://sourceforge.net/projects/batchccews/ (as of this writing, the latest H264Info release is "Alpha 0.13").
Simply run the program, enter your source video stream, "video.h264", for the input file, "video-changed.h264" for the output file, and put 4.1 in the Level box. LEAVE EVERYTHING ELSE BLANK.
When you hit the Start button, H264INFO will read the input file and create a new packet/block (I'm not sure which is the correct terminology for this) using the updated information you gave it.
Because the program has to interpret each source packet and build each output packet, the processing can take some time. Also, you'll have to have enough disk space for both "video.h264" and "video-changed.h264", although you can delete "video.h264" as soon as this step is completed.
Continue to step 4A.
Method B: BYTE EDITING
Instead of properly updating the profile level for every packet in the video stream, we can just update the first packet. This has the advantage of being very fast and not requiring disk space for a second copy of the "video.h264" file - we can just change the right byte in "video.h264" directly.
There's a big "however" here, though: this only worked for me when using the MP4BOX.EXE method in the muxing step below. If you use this method and then mux the video and audio streams with something other than MP4BOX.EXE, you end-up with the ol' "Unsupported Format" icon on the PS3.
I suspect MP4BOX.EXE reads the profile level in the first packet and writes that same level in all other packets as it does its muxing, while other tools write the profile level information from the source stream all the way through without change. Or something like that - a little more investigative work will reveal the details.
So why not just always use MP4BOX.EXE for muxing? The reason is that MP4BOX.EXE only accepts audio in AAC or MP3 formats. If the audio in your MKV file is already in one of these formats or you don't mind converting it, then you're all set. I chose to convert the AC3 in my source file to AAC because the PS3 has an easier time playing it.
Ok, so how do you edit the correct byte?
You'll need a hex/binary editor for this (I use XVI32 - http://www.chmaas.handshake.de/delphi/freeware/xvi32/xvi32.htm - but it has the disadvantage of loading the entire file into memory, which will be a problem in many cases).
Open "video.h264" in the hex editor. Right at the beginning of the file you should see:
00 00 00 01 67 64 00 33
I don't know all the gritty details, but the "000001" should be the "start code" and "67" is the "NAL type". "640033" is what we really care about. "64" indicates "High Level". "33" is "51" in decimal, so that's "Profile Level 5.1". All we need to do is change that "33" into a "29" (which is "41" in decimal).
I wrote a little utility to change bytes like this. There are others out there, but I couldn't find one that you could ask to stop after it found and replaced the first match (you don't want it finding and replacing other "640033" further on in the file that may have nothing to do with the profile level).
Here's how you use it:
binreplace.exe video.h264 0167640033 0167640029
The string after the name of the input file is a string of hex bytes it should search for, "0167640033". We could've just said "640033" or even just "33", but the more specific we are, the less chance there is of accidentally finding and changing something that wasn't the profile level. The second string is the replacement bytes.
BINREPLACE.EXE works very quickly and can deal with files over 4GB in size.
Continue to step 4B.
Continued in next post