VLC video streamed video is not working due to it saved as corrupted video

215 Views Asked by At

I have recorded a video using VLC stream. At the end of the record, I clicked the stop button and closed the player within a few seconds. now the video is not playable I have used this feature before and it worked well.

Due to the player's quick close, I assume the video is not working now. I check the codec details and it's missing. workable videos have H264 - MPEG-4 VAC.

is there any way to fix this? I have attached details of the playable video and the current video.a video taken from the same way and the current video

OS - Windows 11

I have tried to convert the video to avi format using vlc but it doesn't start the converting. I have tried to update the player but it is the latest version.

1

There are 1 best solutions below

2
On

First check if the following tool will display your first frame...
(only works with a VLC recordings @ 720p)

Tool: Preview of first frame from corrupted MP4

If yes, then your MP4 is structured as following (showing first 64 bytes):

00 00 00 18 66 74 79 70 69 73 6F 6D 00 00 00 00     ....ftypisom....
6D 70 34 31 61 76 63 31 00 00 00 00 6D 64 61 74     mp41avc1....mdat
00 00 00 00 00 00 00 00 00 00 02 B0 06 05 FF FF     ...........°..ÿÿ
AC DC 45 E9 BD E6 D9 48 B7 96 2C D8 20 D9 23 EE     ¬ÜEé½æÙH·–,Ø Ù#î

where:
The left side is your bytes (written as Hex characters).
The right side is the decoded UTF-8 text (where possible to decode).

The hex digits 6D 64 61 74 are the beginning of your file's MDAT (Media Data) section. The previous -4 bytes are 00 00 00 00 because VLC does not yet know how large the recording is (until you finish, then it updates that placeholder 0 size into the real number).

The next line has 06 (which is the SEI data) and where the previous -4 bytes are giving a size of (hex) 00 00 02 B0 (or in decimal digits: size of 688 bytes).

You can test: console.log( "Size is... " + 0x000002B0 ); //gives 688
Javascript console always prints out as decimal format, to input a hex value just prefix the hex with 0x (and no spaces between the hex digits).

SEI itself is not a video frame just some extra data that is useful to the MP4 decoder. To reduce playback problems, just include it in your Output followed next by adding the first keyframe.

Always use a hex editor to double-check when working with file bytes

From research you will learn that an MP4 file is divided into two main sections. There is moov which holds the metadata (required for decoder setup and also for the byte positions of each frame, etc). The other section is mdat and this section holds the raw audio/video bytes.

A corrupted VLC recording (into MP4) only has the mdatsection.

An MP4's mdat section has this chunk structure:

[ x4 bytes = chunk SIZE ] [ xN bytes = chunk DATA ]

Repair as MP4 (hardest)

To repair you can use an existing MP4 to know the required "atoms" and copy them over into a new (repaired) set of bytes. You need to edit a section called the Sample Table (find stbl in the file) and update those details (which frames are keyframes? Which byte positions? Which timestamps for frames? etc).

More info: MP4 Atom parsing - How To Configure Time

Repair as H.264 (easiest)

The easiest fix is to try to extract the H.264 frames manually from the MP4 and then later use FFmpeg (or VLC) to combine these video frames with your previously extracted audio (from using the repair software).

To extract video frames, you need to cycle through the chunks (called NAL units) inside the MP4.

Your first NALU (of type SEI) is at a position (also called offset) of 44. From that byte position you can step backwards by four bytes, and then from that new position you can now get the length of NALU by reading those 4 bytes (as one 32-bit unsigned integer, it is unsigned because we don't expect to see any minus symbol, only getting back a positive number).

I will throw in some utility functions to get you started:

To read a 4-byte value from a position in Array:

function read_UInt32_BE_in_Array( in_array, startPos )
{
    return ( (in_array[ startPos+0 ]) << 24 | (in_array[ startPos+1 ]) << 16 | (in_array[ startPos+2 ]) << 8 | (in_array[ startPos+3 ]) );
}

To write a 4-byte value into a position in Array:

function write_UInt32_BE_in_Array( in_val, in_array, startPos )
{
    in_array[ startPos+0 ] = ( (in_val >> 24) & 0x000000FF );
    in_array[ startPos+1 ] = ( (in_val >> 16) & 0x000000FF );
    in_array[ startPos+2 ] = ( (in_val >>  8) & 0x000000FF );
    in_array[ startPos+3 ] = ( (in_val >>  0) & 0x000000FF );
}

The process (in pseudo-code):

myCurrentPos = 44; //# start of SEI data
type_NALU = myBytes[ myCurrentPos ]; //# check NALU type, should be a 6 if SEI data
sizePos = (myCurrentPos - 4); //# go back -4 steps to reach "size" bytes
sizeNum = read_32bit_BigEndian_at_Pos( sizePos ); //# read the 4 size bytes (in Big Endian format)

//# copy bytes (Array slots) from offset "myCurrentPos" up to position of +"sizeNum".

//# skip to next frame
myCurrentPos += ( sizeNum + 4 );
type_NALU = myBytes[ myCurrentPos ]; //# check NALU type, is a 0x65 (dec: 101) if Keyframe data.

//# repeat process of re-reading "sizePos" and "sizeNum" and then copy by this length.
  • Copy only NALU types of (hex format): 0x06, 0x65, 0x41, 0x42 and 0x43
    (or same in decimal format: 6, 101, 65, 66, 67).
  • If NALU is not that type then skip it by using its size to get to the next NALU.
  • Use array.slice() to copy/extract Input byte values into a new Output array

In your Output array (per frame)...

  • First write four bytes: 00 00 00 01 (creates an H264 start code for new data).
  • Then paste in your copied "chunk" bytes.
  • Repeat for another frame until end.

Finally save output file as test.h264 and try to play in a media player.
Next use FFmpeg or VLC to combine the H264 video file with the extracted MP3 data.