How to use libmp4v2
MPEG4ファイルを作成する
const char* filename = "output.mp4"; MP4FileHandle hFile = MP4Create(filename, MP4_DETAILS_ERROR, 0);
このように、とにかく作るだけなら簡単にできる。詳細は不明だが、MP4ファイルが作成される。引数は、このままでよい。
映像トラック (MPEG4 AVC/H.264) を追加する
MP4TrackId videoTrack; //トラック番号を保持 int width = 720; //MP4ファイルの横幅 int height = 480; //MP4ファイルの縦幅 MP4SetVideoProfileLevel(hFile, 0x15); //映像プロファイルレベルの指定 おまじないのようなもの // MP4ファイルに、H.264ビデオトラックを追加する videoTrack = MP4AddH264VideoTrack(hFile, scale, MP4_INVALID_DURATION, width, height, sps[1], //AVCProfileIndication sps[2], //profile_compat sps[3], //AVCLevelIndication 3);
// SPSヘッダを書き込む MP4AddH264SequenceParameterSet(hFile, videoTrack, sps, spsLen)); // PPSヘッダを書き込む MP4AddH264PictureParameterSet(hFile, videoTrack, pps, ppsLen));
音声トラック (MPEG4 AAC)を追加する
MP4TrackId audioTrack; //トラック番号を保持 audioTrack = MP4AddAudioTrack(hFile, samplerate, //サンプルレートをスケールに使うと簡単 MP4_INVALID_DURATION, //こういうもの MP4_MPEG4_AUDIO_TYPE); //こういうもの
MP4SetAudioProfileLevel(hFile, 0x0F); //音声プロファイルレベルの指定 おまじないのようなもの
//音声トラック固有(AACコーデック)の情報をヘッダに書き込む MP4SetTrackESConfiguration(hFile, audioTrack, asc, ascLen);
タイムスケールとは?
今まで、映像をデコードする、音声をデコードする、その結果何バイトのデータが得られたという話題については記してきたが、一体そのデータが人間の感覚でいう、"何秒であるか"ということはまだ説明していない。機械はそういう人間に便利な事柄を理解してくれるはずはなく、当然この何秒といったことを表現するには別の概念と規格を導入する必要がある。こと、このムービーに関しては、"タイムスケール"という概念で規定される。
簡単にいうとタイムスケールは、"何をもって1秒とするか"、という"物差し"を規定するものである。
例えば映像に関して、よく30fpsと言うことが聞かれる。FPSとは、frame per secondで、一秒間に何枚映像のフレームがあるかという単位記号である。映像がぱらぱら漫画のように高速に入れ替わっていることはご存じであろう。この場合、1秒間に30枚なので、タイムスケールは30、1フレームの長さは1なので丁度30枚を書き込むと1秒となる。また映像1枚が流れる時間は、1 ÷ 30 = 0.033(秒/枚)である。このようにすることで、スケールと1単位の長さが表現される。
ただし、映像に関しては90000タイムスケールが一般的に用いられる。理由は説明し難いが、DTSと呼ばれる概念と関わってくるからである(と思う)。実例としては、日本のNTSC映像は、インターレースの29.97fpsの映像である。この人間にとって中途半端な小数点のタイムを表現するには、タイムスケール90000、1フレーム長3003を用いる(90000 ÷ 3003 = 29.97)。30000:1001でも良いではないかとつっこめるが、やはりデコードで得られるDTSが3003など、90000タイムスケールを想定した値を渡してくるのでこの方が都合がよい。
昔何かの文献で読んだ話だが、なぜインターレースの映像なのかというと、昔のテレビの性能が低かったからだそうだ。なんというか、"残念〜"な規格である。
音声はどうだろうか。音の概念は掴みがたいものであるが、よく波に例えられることがある。sin波などがそれであるが、この機械の世界はディジタルであるので、波のような連続の値は現実として用いることが出来ない。そこで、波をある区間で区切って飛び飛びの値で表現したのが、ディジタル音声で、その細かさがサンプリングレートである。このサンプリングレートは48kHzなどで表現される。このHzという単位は1秒間に何回波の周期があるかという単位であるが、ディジタル音声に関しては、何個の音声データがあるのかと、捉えることができる。よって、48kHzの場合は1秒間に48000個の音声データがあるのである。つまり、この48000をタイムスケールに用いると、処理が容易になる。
MPEG4では、映像と音声で別々のタイムスケールを用いることが出来る。よって自然な形のエンコードソフトを作成する際には、映像タイムスケールは90000、音声タイムスケールは音声のサンプリングレート(48000)などを利用すると良い(というか簡単)。
映像データを書き込む
エンコードにより得られた映像データを、MP4ファイルに書き込む。
MP4WriteSample(hFile, videoTrack, //ビデオトラック data, //エンコードデータそのもの dataSize, //データのサイズ(バイト) duration, //フレームの長さ 0, //レンダリングオフセット.後に説明 flag)); //シンクロナイズフラグ.後に説明
音声データを書き込む
終了
エンコードが終了し、必要となるデータを全て書き込んだ後は、MP4ファイルを正しく閉じる必要がある。閉じないで終了した場合は、もちろん再生が出来ないゴミファイルになってしまうので注意。以下に掲載する、いかにもクローズな関数で、MP4ファイルに関する操作が終了する。
MP4Close(hFile);
ここで1点注意事項として、デコードコーデックや、エンコードコーデックのどれよりも早く、MP4ファイルを閉じるべきである。コーデックによっては、クローズで不正終了し、結果MP4ファイルを閉じる前にソフトが落ちてしまうことがあるからである。