Read/Write .MP4 Files WITHOUT Library

Hi everyone,

I need to make a personal library that can read, manipulate, and write .MP4 files. And I need to do it without libraries.

How do you read/write an .mp4 file in C++?
Like any file format.
1. Know the format exactly.
2. Decide what data you need to store/process
3. Do the necessary operations. You know what there is to read. Write in a way that produces valid mp4.

All files contain just bytes. C++ can read those bytes as binary or as they were text. You simply use the operations that match the actual file content.
Do you know of any easily readable explanations or tables of the .mp4 format? Everything I found is extremely dry, unnecessarily verbose and makes it harder than it has to be.

If you have a fav source of file formats plz let me know guys!
> Everything I found is extremely dry, unnecessarily verbose and makes it harder than it has to be.
That's why we have libraries.

Technical documents are dry because they have to be very precise.
Flowery waffle may be easy to follow, but it doesn't make for a good specification.


> If you have a fav source of file formats plz let me know guys!
Just google "mp4 file format"
We can't tell you what you would be consider to be "easy to read".
Ok Salem, thanks
@Salem C @keskiverto

See this documentation:
http://xhelmboyx.tripod.com/formats/mp4-layout.txt

If you search for:
4 bytes video frame pixel size

You'll find the line.

HOW DO I KNOW THE OFFSET FROM THE START OF THE FILE?
HOW DO I KNOW THE OFFSET FROM THE START OF THE FILE?
Why do you shout?
Yes, I found the line "4 bytes video frame pixel size". And I found antecedent many other lines. To get the offset of your value in question, just sum up the length of all preceding values.
Do you mean to go line by line and add up the bytes?
If this seems unfamiliar to you (just reading a file one byte at a time, and moving around using seek), then you have some basic knowledge to acquire before attempting what you want.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include <fstream>
using namespace std;

int main ( ) {
  ifstream fin("proj.cpp");
  char ch;
  while ( fin.get(ch) ) {
    cout << ch << " " << (unsigned)ch << endl;
    if ( ch == '\n' ) {
      // skip some characters
      fin.seekg(10,ios_base::cur);
    }
  }
}
Do you mean to go line by line and add up the bytes?


In principle, yes. But.. that would be too easy. First get the 'file identification', at first glance it seems to me the content of the 'media data box' depends on it. Then, find the location of the 'media data box', this may also be at the end of the file. My suggestion: to build your query routine convert a sample media file to hex, take it to an editor and thinly slice it to one token per line according the spec you linked, tag the designation to every value and check if its content is reasonable. Mark values that denote variable "jumps" or offsets. After you found in that manner short unsigned width + short unsigned height you are looking for, you may start coding your query routine. Similar I once did with TIFF, first it looks awful, but then it's awesome ;)
Thanks @MikeStgt! Made a lot of sense.
Note that parsing the MP4 format is only ~10% of the way to a complete solution. MP4 is just a container for various streams (audio, video, subtitles, etc.). After parsing MP4 you'll get a bunch of packets of compressed data. You still need a codec to decompress that data into a frame of video, or a segment of audio. And an MP4 file may encode its streams using any of several different codecs.
Are you really sure you want to head down this road?
Last edited on
@jpao, in case you didn't get the "bottom line" from the posts above, let me be blunt.

You're trying to do something you'll find nearly impossible (so impractical you shouldn't even begin).

I say that because this is like that cliche, "if you have to ask the price, you probably can't afford it".

If you were of sufficiently advanced skill you'd already know what's ahead, and take this as a message from your future self when you are an expert (sending a message back in time) - it will take years, so just use a library for this.
"if you have to ask the price, you probably can't afford it"
Nice! That saying is new to me :) Thank you.
(Little subject drift) Reminds me an occurrence once at an art fair, where I found a little gem that would do well in my living room, from Egon Schiele, a drawing of a piano player, can't remember his name, https://media.timeout.com/images/101779333/630/472/image.jpg
When I asked for the price I got told "one-point-three million" -- and after a small break (watching how I react) -- "British pounds".
Perfectly probating the a. m. saying. (Then I asked if I could take a photo of it, and to my astonishment the answer was yes.)

Back to the subject: take Niccolo's warning for serious in case you plan to replace VLC by something better. If it's only about reading some meta data, well, why not, if you have enough time and you fear no pain, do it. But your code will turn out as extremely dry as the unnecessarily verbose specs you disliked. Today I looked into my Query-TIFF routine, if I could show it as an example, but no, it's no help. It looks extremely dry, it is from 2001 -- but I am still proud as hell :)
Program to dump the section codes and lengths in an mp4 file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <fstream>
#include <cstdint>

bool read32(std::ifstream& f, uint32_t& n) {
    f.read((char*)&n, sizeof n);
    // Comment this out if your machine is big-endian.
    n = n >> 24 | n << 24 | (n >> 8 & 0xff00) | (n << 8 & 0xff0000);
    return bool(f);
}

void print_chars(uint32_t n) {    // assumes little-endian
    std::cout << (char)(n >> 24)
              << (char)(n >> 16 & 0xff)
              << (char)(n >>  8 & 0xff)
              << (char)(n       & 0xff);
}

int main() {
    std::ifstream f("test.mp4", f.in|f.binary);
    if (!f) { std::cerr << "Cannot open file.\n"; return 1; }
    for (uint32_t size; read32(f, size); ) {
        uint32_t type;
        read32(f, type);
        print_chars(type);
        std::cout << "  " << size << '\n';
        f.ignore(size - 8);
    }
}

But it's really not worth writing such a thing yourself.
Try something like http://atomicparsley.sourceforge.net/
Last edited on
Thanks for taking the time to put forward all your suggestions guys!
Topic archived. No new replies allowed.