| // 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 <strmif.h> | |
| #include "webmconstants.hpp" | |
| #include "webmmuxcontext.hpp" | |
| #include <cstdlib> | |
| #include <cassert> | |
| #include <algorithm> | |
| namespace WebmMuxLib | |
| { | |
| StreamAudio::AudioFrame::AudioFrame() | |
| { | |
| } | |
| StreamAudio::StreamAudio( | |
| Context& ctx, | |
| const BYTE* pb, | |
| ULONG cb) : | |
| Stream(ctx), | |
| m_pFormat(malloc(cb)), | |
| m_cFormat(cb) | |
| { | |
| assert(m_pFormat); | |
| memcpy(m_pFormat, pb, cb); | |
| } | |
| StreamAudio::~StreamAudio() | |
| { | |
| free(m_pFormat); | |
| } | |
| bool StreamAudio::Wait() const | |
| { | |
| return m_context.WaitAudio(); | |
| } | |
| const void* StreamAudio::GetFormat(ULONG& cb) const | |
| { | |
| cb = m_cFormat; | |
| return m_pFormat; | |
| } | |
| void StreamAudio::WriteTrackType() | |
| { | |
| WebmUtil::EbmlScratchBuf& buf = m_context.m_buf; | |
| buf.WriteID1(WebmUtil::kEbmlTrackTypeID); | |
| buf.Write1UInt(1); | |
| buf.Serialize1UInt(WebmUtil::kEbmlTrackTypeAudio); | |
| } | |
| void StreamAudio::WriteTrackSettings() | |
| { | |
| WebmUtil::EbmlScratchBuf& buf = m_context.m_buf; | |
| // we need the starting length of |buf| to properly calculate | |
| // |num_bytes_to_ignore| | |
| const uint64 buf_start_len = buf.GetBufferLength(); | |
| buf.WriteID1(WebmUtil::kEbmlAudioSettingsID); | |
| // store audio settings offset for patching later | |
| const uint64 audio_len_offset = buf.GetBufferLength(); | |
| // We must exclude |num_bytes_to_ignore| from the size we obtain from | |
| // |buf|. The value from |buf| includes the bytes storing all preceding | |
| // data in the track entry -- using it as-is would result in an invalid | |
| // tracks element. | |
| const uint64 num_bytes_to_ignore = buf_start_len + 1 + sizeof(uint16); | |
| // reserve 2 bytes for size of settings | |
| buf.Serialize2UInt(0); | |
| const uint32 samples_per_sec_ = GetSamplesPerSec(); | |
| assert(samples_per_sec_ > 0); | |
| const float samples_per_sec = static_cast<float>(samples_per_sec_); | |
| buf.WriteID1(WebmUtil::kEbmlSamplingFrequencyID); | |
| buf.Write1UInt(4); | |
| buf.Serialize4Float(samples_per_sec); | |
| const uint8 channels = GetChannels(); | |
| assert(channels > 0); | |
| buf.WriteID1(WebmUtil::kEbmlChannelsID); | |
| buf.Write1UInt(1); | |
| buf.Serialize1UInt(channels); | |
| const uint64 audio_len = buf.GetBufferLength() - num_bytes_to_ignore; | |
| buf.RewriteUInt(audio_len_offset, audio_len, sizeof(uint16)); | |
| } | |
| #if 0 | |
| void StreamAudio::AudioFrame::Write( | |
| const Stream& s, | |
| ULONG cluster_timecode) const | |
| { | |
| EbmlIO::File& file = s.m_context.m_file; | |
| //block = 1 byte ID + 4 byte size + f->size | |
| //block duration = 1 byte ID + 1 byte size + 1 byte value | |
| //reference block = 1 byte ID + 2 byte size + 2(?) byte signed value | |
| const ULONG block_size = 1 + 2 + 1 + GetSize(); //tn, tc, flg, f | |
| const ULONG block_group_size = 1 + 4 + block_size; //block id, size, payload | |
| file.WriteID1(0xA0); //block group ID | |
| file.Write4UInt(block_group_size); //size of payload for this block group | |
| #ifdef _DEBUG | |
| const __int64 pos = file.GetPosition(); | |
| #endif | |
| //begin block | |
| file.WriteID1(0xA1); //Block ID | |
| file.Write4UInt(block_size); | |
| const int tn_ = s.GetTrackNumber(); | |
| assert(tn_ > 0); | |
| assert(tn_ <= 127); | |
| const BYTE tn = static_cast<BYTE>(tn_); | |
| file.Write1UInt(tn); //track number | |
| const ULONG ft = GetTimecode(); | |
| { | |
| const LONG tc_ = LONG(ft) - LONG(cluster_timecode); | |
| assert(tc_ >= SHRT_MIN); | |
| assert(tc_ <= SHRT_MAX); | |
| const SHORT tc = static_cast<SHORT>(tc_); | |
| file.Serialize2SInt(tc); //relative timecode | |
| } | |
| const BYTE flags = 0; | |
| file.Write(&flags, 1); //written as binary, not uint | |
| file.Write(GetData(), GetSize()); //frame | |
| //end block | |
| #ifdef _DEBUG | |
| const __int64 newpos = file.GetPosition(); | |
| assert((newpos - pos) == block_group_size); | |
| #endif | |
| } | |
| #endif | |
| bool StreamAudio::AudioFrame::IsKey() const | |
| { | |
| return true; | |
| } | |
| StreamAudio::frames_t& StreamAudio::GetFrames() | |
| { | |
| return m_frames; | |
| } | |
| void StreamAudio::Flush() | |
| { | |
| m_context.FlushAudio(this); | |
| } | |
| } //end namespace WebmMuxLib |