void writeVideoTrack(EbmlGlobal *glob, unsigned int trackNumber, int flagLacing, const char *codecId, unsigned int pixelWidth, unsigned int pixelHeight, unsigned int displayWidth, unsigned int displayHeight, double frameRate) { EbmlLoc start; UInt64 trackID; Ebml_StartSubElement(glob, &start, TrackEntry); Ebml_SerializeUnsigned(glob, TrackNumber, trackNumber); trackID = generateTrackID(trackNumber); Ebml_SerializeUnsigned(glob, TrackUID, trackID); Ebml_SerializeString(glob, CodecName, "VP8"); // TODO shouldn't be fixed Ebml_SerializeUnsigned(glob, TrackType, 1); // video is always 1 Ebml_SerializeString(glob, CodecID, codecId); { EbmlLoc videoStart; Ebml_StartSubElement(glob, &videoStart, Video); Ebml_SerializeUnsigned(glob, PixelWidth, pixelWidth); Ebml_SerializeUnsigned(glob, PixelHeight, pixelHeight); if (pixelWidth != displayWidth) { Ebml_SerializeUnsigned(glob, DisplayWidth, displayWidth); } if (pixelHeight != displayHeight) { Ebml_SerializeUnsigned(glob, DisplayHeight, displayHeight); } Ebml_SerializeFloat(glob, FrameRate, frameRate); Ebml_EndSubElement(glob, &videoStart); // Video } Ebml_EndSubElement(glob, &start); // Track Entry }
void write_webm_file_header(struct EbmlGlobal *glob, const vpx_codec_enc_cfg_t *cfg, const struct vpx_rational *fps, stereo_format_t stereo_fmt, unsigned int fourcc) { EbmlLoc start; EbmlLoc trackStart; EbmlLoc videoStart; unsigned int trackNumber = 1; uint64_t trackID = 0; unsigned int pixelWidth = cfg->g_w; unsigned int pixelHeight = cfg->g_h; /* Write the EBML header. */ Ebml_StartSubElement(glob, &start, EBML); Ebml_SerializeUnsigned(glob, EBMLVersion, 1); Ebml_SerializeUnsigned(glob, EBMLReadVersion, 1); Ebml_SerializeUnsigned(glob, EBMLMaxIDLength, 4); Ebml_SerializeUnsigned(glob, EBMLMaxSizeLength, 8); Ebml_SerializeString(glob, DocType, "webm"); Ebml_SerializeUnsigned(glob, DocTypeVersion, 2); Ebml_SerializeUnsigned(glob, DocTypeReadVersion, 2); Ebml_EndSubElement(glob, &start); /* Open and begin writing the segment element. */ Ebml_StartSubElement(glob, &glob->startSegment, Segment); glob->position_reference = ftello(glob->stream); glob->framerate = *fps; write_webm_seek_info(glob); /* Open and write the Tracks element. */ glob->track_pos = ftello(glob->stream); Ebml_StartSubElement(glob, &trackStart, Tracks); /* Open and write the Track entry. */ Ebml_StartSubElement(glob, &start, TrackEntry); Ebml_SerializeUnsigned(glob, TrackNumber, trackNumber); glob->track_id_pos = ftello(glob->stream); Ebml_SerializeUnsigned32(glob, TrackUID, trackID); Ebml_SerializeUnsigned(glob, TrackType, 1); Ebml_SerializeString(glob, CodecID, fourcc == VP8_FOURCC ? "V_VP8" : "V_VP9"); Ebml_StartSubElement(glob, &videoStart, Video); Ebml_SerializeUnsigned(glob, PixelWidth, pixelWidth); Ebml_SerializeUnsigned(glob, PixelHeight, pixelHeight); Ebml_SerializeUnsigned(glob, StereoMode, stereo_fmt); Ebml_EndSubElement(glob, &videoStart); /* Close Track entry. */ Ebml_EndSubElement(glob, &start); /* Close Tracks element. */ Ebml_EndSubElement(glob, &trackStart); /* Segment element remains open. */ }
int Ebml_WriteWebMSeekInfo(EbmlGlobal *ebml) { int rc = VINF_SUCCESS; /* Save the current file pointer */ uint64_t pos = RTFileTell(ebml->file); if (ebml->seek_info_pos) rc = RTFileSeek(ebml->file, ebml->seek_info_pos, RTFILE_SEEK_BEGIN, NULL); else ebml->seek_info_pos = pos; { uint64_t start; if (RT_SUCCESS(rc)) rc = ebml_StartSubElement(ebml, &start, SeekHead); if (RT_SUCCESS(rc)) rc = Ebml_WriteWebMSeekElement(ebml, Tracks, ebml->track_pos); if (RT_SUCCESS(rc)) rc = Ebml_WriteWebMSeekElement(ebml, Cues, ebml->cue_pos); if (RT_SUCCESS(rc)) rc = Ebml_WriteWebMSeekElement(ebml, Info, ebml->segment_info_pos); if (RT_SUCCESS(rc)) rc = ebml_EndSubElement(ebml, start); } { //segment info uint64_t startInfo; uint64_t frame_time; frame_time = (uint64_t)1000 * ebml->framerate.den / ebml->framerate.num; ebml->segment_info_pos = RTFileTell(ebml->file); if (RT_SUCCESS(rc)) rc = ebml_StartSubElement(ebml, &startInfo, Info); if (RT_SUCCESS(rc)) rc = Ebml_SerializeUnsigned(ebml, TimecodeScale, 1000000); if (RT_SUCCESS(rc)) rc = Ebml_SerializeFloat(ebml, Segment_Duration, (double)(ebml->last_pts_ms + frame_time)); char szVersion[64]; RTStrPrintf(szVersion, sizeof(szVersion), "vpxenc%", ebml->debug ? vpx_codec_version_str() : ""); if (RT_SUCCESS(rc)) rc = Ebml_SerializeString(ebml, MuxingApp, szVersion); if (RT_SUCCESS(rc)) rc = Ebml_SerializeString(ebml, WritingApp, szVersion); if (RT_SUCCESS(rc)) rc = ebml_EndSubElement(ebml, startInfo); } return rc; }
//------------------------------------------------------------------ void write_webm_file_header(EbmlGlobal *global, const vpx_codec_enc_cfg_t *cfg, const struct vpx_rational *fps) { off_t start; off_t trackStart; off_t videoStart; unsigned int trackNumber = 1; uint64_t trackID = 0; unsigned int pixelWidth = cfg->g_w; unsigned int pixelHeight = cfg->g_h; /* Write the EBML header. */ Ebml_StartSubElement(global, &start, EBML); Ebml_SerializeUnsigned(global, EBMLVersion, 1); Ebml_SerializeUnsigned(global, EBMLReadVersion, 1); Ebml_SerializeUnsigned(global, EBMLMaxIDLength, 4); Ebml_SerializeUnsigned(global, EBMLMaxSizeLength, 8); Ebml_SerializeString(global, DocType, "webm"); Ebml_SerializeUnsigned(global, DocTypeVersion, 2); Ebml_SerializeUnsigned(global, DocTypeReadVersion, 2); Ebml_EndSubElement(global, &start); /* Open and begin writing the segment element. */ Ebml_StartSubElement(global, &global->startSegment, Segment); global->position_reference = ftello(global->stream); global->framerate = *fps; write_webm_seek_info(global); /* Open and write the Tracks element. */ global->track_pos = ftello(global->stream); Ebml_StartSubElement(global, &trackStart, Tracks); /* Open and write the Track entry. */ Ebml_StartSubElement(global, &start, TrackEntry); Ebml_SerializeUnsigned(global, TrackNumber, trackNumber); global->track_id_pos = ftello(global->stream); Ebml_SerializeUnsigned32(global, TrackUID, trackID); Ebml_SerializeUnsigned(global, TrackType, 1); Ebml_SerializeString(global, CodecID, "V_VP8"); Ebml_StartSubElement(global, &videoStart, Video); Ebml_SerializeUnsigned(global, PixelWidth, pixelWidth); Ebml_SerializeUnsigned(global, PixelHeight, pixelHeight); Ebml_SerializeUnsigned(global, StereoMode, STEREO_FORMAT_MONO); Ebml_EndSubElement(global, &videoStart); /* Close Track entry. */ Ebml_EndSubElement(global, &start); /* Close Tracks element. */ Ebml_EndSubElement(global, &trackStart); /* Segment element remains open. */ }
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; }
void write_webm_seek_info(struct EbmlGlobal *ebml) { off_t pos; EbmlLoc start; EbmlLoc startInfo; uint64_t frame_time; char version_string[64]; /* Save the current stream pointer. */ pos = ftello(ebml->stream); if (ebml->seek_info_pos) fseeko(ebml->stream, ebml->seek_info_pos, SEEK_SET); else ebml->seek_info_pos = pos; Ebml_StartSubElement(ebml, &start, SeekHead); write_webm_seek_element(ebml, Tracks, ebml->track_pos); write_webm_seek_element(ebml, Cues, ebml->cue_pos); write_webm_seek_element(ebml, Info, ebml->segment_info_pos); Ebml_EndSubElement(ebml, &start); /* Create and write the Segment Info. */ if (ebml->debug) { strcpy(version_string, "vpxenc"); } else { strcpy(version_string, "vpxenc "); strncat(version_string, vpx_codec_version_str(), sizeof(version_string) - 1 - strlen(version_string)); } frame_time = (uint64_t)1000 * ebml->framerate.den / ebml->framerate.num; ebml->segment_info_pos = ftello(ebml->stream); Ebml_StartSubElement(ebml, &startInfo, Info); Ebml_SerializeUnsigned(ebml, TimecodeScale, 1000000); Ebml_SerializeFloat(ebml, Segment_Duration, (double)(ebml->last_pts_ms + frame_time)); Ebml_SerializeString(ebml, 0x4D80, version_string); Ebml_SerializeString(ebml, 0x5741, version_string); Ebml_EndSubElement(ebml, &startInfo); }
void writeHeader(EbmlGlobal *glob) { EbmlLoc start; Ebml_StartSubElement(glob, &start, EBML); Ebml_SerializeUnsigned(glob, EBMLVersion, 1); Ebml_SerializeUnsigned(glob, EBMLReadVersion, 1); Ebml_SerializeUnsigned(glob, EBMLMaxIDLength, 4); Ebml_SerializeUnsigned(glob, EBMLMaxSizeLength, 8); Ebml_SerializeString(glob, DocType, "webm"); Ebml_SerializeUnsigned(glob, DocTypeVersion, 2); Ebml_SerializeUnsigned(glob, DocTypeReadVersion, 2); Ebml_EndSubElement(glob, &start); }
//------------------------------------------------------------------ void write_webm_seek_info(EbmlGlobal *global) { off_t pos; off_t start; off_t startInfo; uint64_t frame_time; char version_string[64]; /* Save the current stream pointer. */ pos = ftello(global->stream); if (global->seek_info_pos) { fseeko(global->stream, global->seek_info_pos, SEEK_SET); } else { global->seek_info_pos = pos; } Ebml_StartSubElement(global, &start, SeekHead); write_webm_seek_element(global, Tracks, global->track_pos); write_webm_seek_element(global, Cues, global->cue_pos); write_webm_seek_element(global, Info, global->segment_info_pos); Ebml_EndSubElement(global, &start); /* Create and write the Segment Info. */ strcpy(version_string, "DesktopCapture v1.0 - libVPX "); strncat(version_string, vpx_codec_version_str(), sizeof(version_string) - 1 - strlen(version_string)); frame_time = (uint64_t) 1000 * global->framerate.den / global->framerate.num; global->segment_info_pos = ftello(global->stream); Ebml_StartSubElement(global, &startInfo, Info); Ebml_SerializeUnsigned(global, TimecodeScale, 1000000); Ebml_SerializeFloat(global, Segment_Duration, (double) (global->last_pts_ms + frame_time)); Ebml_SerializeString(global, MuxingApp, version_string); Ebml_SerializeString(global, WritingApp, version_string); Ebml_EndSubElement(global, &startInfo); }
void writeVideoTrack(EbmlGlobal *glob, unsigned int trackNumber, int flagLacing, char *codecId, unsigned int pixelWidth, unsigned int pixelHeight, double frameRate) { EbmlLoc start; Ebml_StartSubElement(glob, &start, TrackEntry); Ebml_SerializeUnsigned(glob, TrackNumber, trackNumber); UInt64 trackID = generateTrackID(trackNumber); Ebml_SerializeUnsigned(glob, TrackUID, trackID); Ebml_SerializeString(glob, CodecName, "VP8"); Ebml_SerializeUnsigned(glob, TrackType, 1); Ebml_SerializeString(glob, CodecID, codecId); { EbmlLoc videoStart; Ebml_StartSubElement(glob, &videoStart, Video); Ebml_SerializeUnsigned(glob, PixelWidth, pixelWidth); Ebml_SerializeUnsigned(glob, PixelHeight, pixelHeight); Ebml_SerializeFloat(glob, FrameRate, frameRate); Ebml_EndSubElement(glob, &videoStart); } Ebml_EndSubElement(glob, &start); }
int Ebml_WriteWebMFileHeader(EbmlGlobal *glob, const vpx_codec_enc_cfg_t *cfg, const struct vpx_rational *fps) { int rc = VINF_SUCCESS; { uint64_t start; rc = ebml_StartSubElement(glob, &start, EBML); if (RT_SUCCESS(rc)) rc = Ebml_SerializeUnsigned(glob, EBMLVersion, 1); if (RT_SUCCESS(rc)) rc = Ebml_SerializeUnsigned(glob, EBMLReadVersion, 1); if (RT_SUCCESS(rc)) rc = Ebml_SerializeUnsigned(glob, EBMLMaxIDLength, 4); if (RT_SUCCESS(rc)) rc = Ebml_SerializeUnsigned(glob, EBMLMaxSizeLength, 8); if (RT_SUCCESS(rc)) rc = Ebml_SerializeString(glob, DocType, "webm"); if (RT_SUCCESS(rc)) rc = Ebml_SerializeUnsigned(glob, DocTypeVersion, 2); if (RT_SUCCESS(rc)) rc = Ebml_SerializeUnsigned(glob, DocTypeReadVersion, 2); if (RT_SUCCESS(rc)) rc = ebml_EndSubElement(glob, start); } { if (RT_SUCCESS(rc)) rc = ebml_StartSubElement(glob, &glob->startSegment, Segment); glob->position_reference = RTFileTell(glob->file); glob->framerate = *fps; if (RT_SUCCESS(rc)) rc = Ebml_WriteWebMSeekInfo(glob); { uint64_t trackStart; glob->track_pos = RTFileTell(glob->file); if (RT_SUCCESS(rc)) rc = ebml_StartSubElement(glob, &trackStart, Tracks); { uint32_t trackNumber = 1; uint32_t trackID = 0; uint64_t start; if (RT_SUCCESS(rc)) rc = ebml_StartSubElement(glob, &start, TrackEntry); if (RT_SUCCESS(rc)) rc = Ebml_SerializeUnsigned(glob, TrackNumber, trackNumber); glob->track_id_pos = RTFileTell(glob->file); ebml_SerializeUnsigned32(glob, TrackUID, trackID); Ebml_SerializeUnsigned(glob, TrackType, 1); //video is always 1 Ebml_SerializeString(glob, CodecID, "V_VP8"); { uint64_t videoStart; if (RT_SUCCESS(rc)) rc = ebml_StartSubElement(glob, &videoStart, Video); uint32_t pixelWidth = cfg->g_w; if (RT_SUCCESS(rc)) rc = Ebml_SerializeUnsigned(glob, PixelWidth, pixelWidth); uint32_t pixelHeight = cfg->g_h; if (RT_SUCCESS(rc)) rc = Ebml_SerializeUnsigned(glob, PixelHeight, pixelHeight); double frameRate = (double)fps->num / (double)fps->den; if (RT_SUCCESS(rc)) rc = Ebml_SerializeFloat(glob, FrameRate, frameRate); if (RT_SUCCESS(rc)) rc = ebml_EndSubElement(glob, videoStart); } if (RT_SUCCESS(rc)) rc = ebml_EndSubElement(glob, start); //Track Entry } if (RT_SUCCESS(rc)) rc = ebml_EndSubElement(glob, trackStart); } // segment element is open } return rc; }