blob: cc25dd7bbbdd2539cab3e51b5ff684c71653fbc8 [file] [log] [blame]
// Copyright (c) 2012 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 <memory>
#include <vector>
#include "encoder/basictypes.h"
#include "encoder/encoder_base.h"
#include "encoder/webm_encoder.h"
// Forward declarations of libwebm muxer types used by |LiveWebmMuxer|.
namespace mkvmuxer {
class Segment;
namespace webmlive {
// Forward declaration of class implementing IMkvWriter interface for libwebm.
class WebmMuxWriter;
struct VorbisCodecPrivate {
: ptr_ident(NULL),
setup_length(0) {}
const uint8* ptr_ident;
int32 ident_length;
const uint8* ptr_comments;
int32 comments_length;
const uint8* ptr_setup;
int32 setup_length;
// WebM muxing object built atop libwebm. Provides buffers containing WebM
// "chunks" of two types:
// Metadata Chunk
// Contains EBML header, segment info, and segment tracks elements.
// Chunk
// A complete WebM cluster element.
// Notes:
// - Only the first chunk written is metadata. All other chunks are clusters.
// - All element size values are set to unknown (an EBML encoded -1).
// - Users MUST call |Init()| before any other method.
// - Users MUST call |Finalize()| to avoid losing the final cluster; libwebm
// must buffer data in some situations to satisfy WebM container guidelines:
// - Users are responsible for keeping memory usage reasonable by calling
// |ChunkReady()| periodically-- when |ChunkReady| returns true,
// |ReadChunk()| will return the complete chunk and discard it from the
// buffer.
class LiveWebmMuxer {
typedef std::vector<uint8> WriteBuffer;
static const uint64 kTimecodeScale = 1000000;
// Status codes returned by class methods.
enum {
// Temporary return code for unimplemented operations.
kNotImplemented = -200,
// Unable to write audio buffer.
kAudioWriteError = -13,
// |WriteAudioBuffer()| called without adding an audio track.
kNoAudioTrack = -12,
// Invalid |VorbisCodecPrivate| passed to |AddTrack()|.
kAudioPrivateDataInvalid = -11,
// |AddTrack()| called for audio, but the audio track has already been
// added.
kAudioTrackAlreadyExists = -10,
// Addition of the audio track to |ptr_segment_| failed.
kAudioTrackError = -9,
// |ReadChunk()| called when no chunk is ready.
kNoChunkReady = -8,
// Buffer passed to |ReadChunk()| was too small.
kUserBufferTooSmall = -7,
// Unable to write video frame.
kVideoWriteError = -6,
// |WriteVideoFrame()| called without adding a video track.
kNoVideoTrack = -5,
// |AddTrack()| called for video, but the video track has already been
// added.
kVideoTrackAlreadyExists = -5,
// Addition of the video track to |ptr_segment_| failed.
kVideoTrackError = -4,
// Something failed while interacting with the muxing library.
kMuxerError = -3,
kNoMemory = -2,
kInvalidArg = -1,
kSuccess = 0,
// Initializes libwebm for muxing in live mode.
// Ignores |cluster_duration| when it's less than 1. |muxer_id| is a user data
// string that can be used to identify the muxer when using multiple
// instances of the muxer.
// Returns |kSuccess| when successful.
int Init(int32 cluster_duration_milliseconds, const std::string& muxer_id);
// Adds an audio track to |ptr_segment_| and returns |kSuccess|. Returns
// |kAudioTrackAlreadyExists| when the audio track has already been added.
// Returns |kAudioTrackError| when adding the track to the segment fails.
int AddTrack(const AudioConfig& audio_config,
const VorbisCodecPrivate& codec_private);
// Adds a video track to |ptr_segment_|, and returns |kSuccess|. Returns
// |kVideoTrackAlreadyExists| when the video track has already been added.
// Returns |kVideoTrackError| when adding the track to the segment fails.
int AddTrack(const VideoConfig& video_config);
// Flushes any queued frames. Users MUST call this method to ensure that all
// buffered frames are flushed out of libwebm. To determine if calling
// |Finalize()| resulted in production of a chunk, call |ChunkReady()| after
// the call to |Finalize()|. Returns |kSuccess| when |Segment::Finalize()|
// returns without error.
int Finalize();
// Writes |vorbis_buffer| to the audio track and returns |kSuccess|. Returns
// |kInvalidArg| when |vorbis_buffer| is empty or contains non-Vorbis audio.
// Returns |kAudioWriteError| when libwebm returns an error.
int WriteAudioBuffer(const AudioBuffer& vorbis_buffer);
// Writes |vpx_frame| to the video track and returns |kSuccess|. Returns
// |kInvalidArg| when |vpx_frame| is empty or contains a non-VPx frame.
// Returns |kVideoWriteError| when libwebm returns an error.
int WriteVideoFrame(const VideoFrame& vpx_frame);
// Returns true and writes chunk length to |ptr_chunk_length| when |buffer_|
// contains a complete WebM chunk.
bool ChunkReady(int32* ptr_chunk_length);
// Moves WebM chunk data into |ptr_buf|. The data has been from removed from
// |buffer_| when |kSuccess| is returned. Returns |kUserBufferTooSmall| if
// |buffer_capacity| is less than |chunk_length|.
int ReadChunk(int32 buffer_capacity, uint8* ptr_buf);
// Accessors.
int64 muxer_time() const { return muxer_time_; }
int64 chunks_read() const { return chunks_read_; }
std::string muxer_id() const { return muxer_id_; }
std::unique_ptr<WebmMuxWriter> ptr_writer_;
std::unique_ptr<mkvmuxer::Segment> ptr_segment_;
uint64 audio_track_num_;
uint64 video_track_num_;
WriteBuffer buffer_;
int64 muxer_time_;
int64 chunks_read_;
std::string muxer_id_;
friend class WebmMuxWriter;
} // namespace webmlive