/* $Id: EbmlWriter.cpp 52316 2014-08-07 14:11:55Z vboxsync $ */ /** @file * EbmlWriter.cpp - EBML writer + WebM container */ /* * Copyright (C) 2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; * you can redistribute it and/or modify it under the terms of the GNU * General Public License (GPL) as published by the Free Software * Foundation, in version 2 as it comes in the "COPYING" file of the * VirtualBox OSE distribution. VirtualBox OSE is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ /* * This code is based on: * * Copyright (c) 2010 The WebM project authors. All Rights Reserved. * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "EbmlWriter.h" #include #include #include #include Ebml::Ebml() {} void Ebml::init(const RTFILE &a_File) { m_File = a_File; } void Ebml::write(const void *data, size_t size) { int rc = RTFileWrite(m_File, data, size, NULL); if (!RT_SUCCESS(rc)) throw rc; } uint64_t WebMWriter::getFileSize() { return RTFileTell(m_File); } WebMWriter::WebMWriter() : m_bDebug(false), m_iLastPtsMs(-1), m_Framerate(), m_uPositionReference(0), m_uSeekInfoPos(0), m_uSegmentInfoPos(0), m_uTrackPos(0), m_uCuePos(0), m_uClusterPos(0), m_uTrackIdPos(0), m_uStartSegment(0), m_uClusterTimecode(0), m_bClusterOpen(false) {} int WebMWriter::create(const char *a_pszFilename) { int rc = RTFileOpen(&m_File, a_pszFilename, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE); if (RT_SUCCESS(rc)) { m_Ebml.init(m_File); } return rc; } void WebMWriter::close() { RTFileClose(m_File); } Ebml &operator<<(Ebml &a_Ebml, const WebMWriter::SimpleBlockData &a_Data) { a_Ebml.serializeConst(); a_Ebml.write(0x10000000u | (Ebml::getSizeOfUInt(a_Data.trackNumber) + 2 + 1 + a_Data.dataSize)); a_Ebml.serializeInteger(a_Data.trackNumber); a_Ebml.write(a_Data.timeCode); a_Ebml.write(a_Data.flags); a_Ebml.write(a_Data.data, a_Data.dataSize); return a_Ebml; } void WebMWriter::writeSeekInfo() { // Save the current file pointer uint64_t uPos = RTFileTell(m_File); if (m_uSeekInfoPos) RTFileSeek(m_File, m_uSeekInfoPos, RTFILE_SEEK_BEGIN, NULL); else m_uSeekInfoPos = uPos; m_Ebml << Ebml::SubStart() << Ebml::SubStart() << Ebml::Const() << Ebml::Var(m_uTrackPos - m_uPositionReference) << Ebml::SubEnd() << Ebml::SubStart() << Ebml::Const() << Ebml::Var(m_uCuePos - m_uPositionReference) << Ebml::SubEnd() << Ebml::SubStart() << Ebml::Const() << Ebml::Var(m_uSegmentInfoPos - m_uPositionReference) << Ebml::SubEnd() << Ebml::SubEnd(); int64_t iFrameTime = (int64_t)1000 * m_Framerate.den / m_Framerate.num; m_uSegmentInfoPos = RTFileTell(m_File); char szVersion[64]; RTStrPrintf(szVersion, sizeof(szVersion), "vpxenc%", m_bDebug ? vpx_codec_version_str() : ""); m_Ebml << Ebml::SubStart() << Ebml::UnsignedInteger(1000000) << Ebml::Float(m_iLastPtsMs + iFrameTime) << Ebml::String(szVersion) << Ebml::String(szVersion) << Ebml::SubEnd(); } int WebMWriter::writeHeader(const vpx_codec_enc_cfg_t *a_pCfg, const struct vpx_rational *a_pFps) { try { m_Ebml << Ebml::SubStart() << Ebml::UnsignedInteger(1) << Ebml::UnsignedInteger(1) << Ebml::UnsignedInteger(4) << Ebml::UnsignedInteger(8) << Ebml::String("webm") << Ebml::UnsignedInteger(2) << Ebml::UnsignedInteger(2) << Ebml::SubEnd(); m_Ebml << Ebml::SubStart(); m_uPositionReference = RTFileTell(m_File); m_Framerate = *a_pFps; writeSeekInfo(); m_uTrackPos = RTFileTell(m_File); m_Ebml << Ebml::SubStart() << Ebml::SubStart() << Ebml::UnsignedInteger(1); m_uTrackIdPos = RTFileTell(m_File); m_Ebml << Ebml::Var(0) << Ebml::UnsignedInteger(1) << Ebml::String("V_VP8") << Ebml::SubStart