void EbmlComposer::GenerateHeader() { // Write the EBML header. EbmlGlobal ebml; // The WEbM header default size usually smaller than 1k. auto buffer = MakeUnique<uint8_t[]>(DEFAULT_HEADER_SIZE + mCodecPrivateData.Length()); ebml.buf = buffer.get(); ebml.offset = 0; writeHeader(&ebml); { EbmlLoc segEbmlLoc, ebmlLocseg, ebmlLoc; Ebml_StartSubElement(&ebml, &segEbmlLoc, Segment); { Ebml_StartSubElement(&ebml, &ebmlLocseg, SeekHead); // Todo: We don't know the exact sizes of encoded data and // ignore this section. Ebml_EndSubElement(&ebml, &ebmlLocseg); writeSegmentInformation(&ebml, &ebmlLoc, TIME_CODE_SCALE, 0); { EbmlLoc trackLoc; Ebml_StartSubElement(&ebml, &trackLoc, Tracks); { // Video if (mWidth > 0 && mHeight > 0) { writeVideoTrack(&ebml, 0x1, 0, "V_VP8", mWidth, mHeight, mDisplayWidth, mDisplayHeight, mFrameRate); } // Audio if (mCodecPrivateData.Length() > 0) { // Extract the pre-skip from mCodecPrivateData // then convert it to nanoseconds. // Details in OpusTrackEncoder.cpp. mCodecDelay = (uint64_t)LittleEndian::readUint16(mCodecPrivateData.Elements() + 10) * PR_NSEC_PER_SEC / 48000; // Fixed 80ms, convert into nanoseconds. uint64_t seekPreRoll = 80 * PR_NSEC_PER_MSEC; writeAudioTrack(&ebml, 0x2, 0x0, "A_OPUS", mSampleFreq, mChannels, mCodecDelay, seekPreRoll, mCodecPrivateData.Elements(), mCodecPrivateData.Length()); } } Ebml_EndSubElement(&ebml, &trackLoc); } } // The Recording length is unknown and // ignore write the whole Segment element size } MOZ_ASSERT(ebml.offset <= DEFAULT_HEADER_SIZE + mCodecPrivateData.Length(), "write more data > EBML_BUFFER_SIZE"); auto block = mClusterBuffs.AppendElement(); block->SetLength(ebml.offset); memcpy(block->Elements(), ebml.buf, ebml.offset); mFlushState |= FLUSH_METADATA; }
void EbmlComposer::GenerateHeader() { // Write the EBML header. EbmlGlobal ebml; // The WEbM header default size usually smaller than 1k. nsAutoArrayPtr<uint8_t> buffer(new uint8_t[DEFAULT_HEADER_SIZE + mCodecPrivateData.Length()]); ebml.buf = buffer.get(); ebml.offset = 0; writeHeader(&ebml); { EbmlLoc segEbmlLoc, ebmlLocseg, ebmlLoc; Ebml_StartSubElement(&ebml, &segEbmlLoc, Segment); { Ebml_StartSubElement(&ebml, &ebmlLocseg, SeekHead); // Todo: We don't know the exact sizes of encoded data and // ignore this section. Ebml_EndSubElement(&ebml, &ebmlLocseg); writeSegmentInformation(&ebml, &ebmlLoc, TIME_CODE_SCALE, 0); { EbmlLoc trackLoc; Ebml_StartSubElement(&ebml, &trackLoc, Tracks); { // Video if (mWidth > 0 && mHeight > 0) { writeVideoTrack(&ebml, 0x1, 0, "V_VP8", mWidth, mHeight, mDisplayWidth, mDisplayHeight, mFrameRate); } // Audio if (mCodecPrivateData.Length() > 0) { writeAudioTrack(&ebml, 0x2, 0x0, "A_VORBIS", mSampleFreq, mChannels, mCodecPrivateData.Elements(), mCodecPrivateData.Length()); } } Ebml_EndSubElement(&ebml, &trackLoc); } } // The Recording length is unknown and // ignore write the whole Segment element size } MOZ_ASSERT(ebml.offset <= DEFAULT_HEADER_SIZE + mCodecPrivateData.Length(), "write more data > EBML_BUFFER_SIZE"); auto block = mClusterBuffs.AppendElement(); block->SetLength(ebml.offset); memcpy(block->Elements(), ebml.buf, ebml.offset); mFlushState |= FLUSH_METADATA; }
int main(int argc, char *argv[]) { // init the datatype we're using for ebml output unsigned char data[8192]; EbmlGlobal ebml; ebml.buf = data; ebml.offset = 0; ebml.length = 8192; writeHeader(&ebml); { EbmlLoc startSegment; Ebml_StartSubElement(&ebml, &startSegment, Segment); // segment { // segment info EbmlLoc startInfo; Ebml_StartSubElement(&ebml, &startInfo, Info); Ebml_SerializeString(&ebml, 0x4D80, "muxingAppLibMkv"); Ebml_SerializeString(&ebml, 0x5741, "writingAppLibMkv"); Ebml_EndSubElement(&ebml, &startInfo); } { EbmlLoc trackStart; Ebml_StartSubElement(&ebml, &trackStart, Tracks); writeVideoTrack(&ebml, 1, 1, "V_MS/VFW/FOURCC", 320, 240, 29.97); // writeAudioTrack(&ebml,2,1, "A_VORBIS", 32000, 1, NULL, 0); Ebml_EndSubElement(&ebml, &trackStart); } { EbmlLoc clusterStart; Ebml_StartSubElement(&ebml, &clusterStart, Cluster); // cluster Ebml_SerializeUnsigned(&ebml, Timecode, 0); unsigned char someData[4] = {1, 2, 3, 4}; writeSimpleBlock(&ebml, 1, 0, 1, 0, 0, someData, 4); Ebml_EndSubElement(&ebml, &clusterStart); } // end cluster Ebml_EndSubElement(&ebml, &startSegment); } // dump ebml stuff to the file FILE *file_out = fopen("test.mkv", "wb"); size_t bytesWritten = fwrite(data, 1, ebml.offset, file_out); fclose(file_out); return 0; }