diff --git a/build/make/Makefile b/build/make/Makefile index 0c5ff64f4c897c1d3cdaf09aa1df2c41a6f8e985..dd7fb4a213fb1b080522cf6982ebee7971b24395 100644 --- a/build/make/Makefile +++ b/build/make/Makefile @@ -147,15 +147,6 @@ $(BUILD_PFX)%.cc.o: %.cc $(if $(quiet),@echo " [CXX] $@") $(qexec)$(CXX) $(INTERNAL_CFLAGS) $(CXXFLAGS) -c -o $@ $< -$(BUILD_PFX)%.cpp.d: %.cpp - $(if $(quiet),@echo " [DEP] $@") - $(qexec)mkdir -p $(dir $@) - $(qexec)$(CXX) $(INTERNAL_CFLAGS) $(CXXFLAGS) -M $< | $(fmt_deps) > $@ - -$(BUILD_PFX)%.cpp.o: %.cpp - $(if $(quiet),@echo " [CXX] $@") - $(qexec)$(CXX) $(INTERNAL_CFLAGS) $(CXXFLAGS) -c -o $@ $< - $(BUILD_PFX)%.asm.d: %.asm $(if $(quiet),@echo " [DEP] $@") $(qexec)mkdir -p $(dir $@) @@ -227,7 +218,7 @@ cond_enabled=$(if $(filter yes,$($(1))), $(call enabled,$(2))) find_file1=$(word 1,$(wildcard $(subst //,/,$(addsuffix /$(1),$(2))))) find_file=$(foreach f,$(1),$(call find_file1,$(strip $(f)),$(strip $(2))) ) -obj_pats=.c=.c.o $(AS_SFX)=$(AS_SFX).o .cc=.cc.o .cpp=.cpp.o +obj_pats=.c=.c.o $(AS_SFX)=$(AS_SFX).o .cc=.cc.o objs=$(addprefix $(BUILD_PFX),$(foreach p,$(obj_pats),$(filter %.o,$(1:$(p))) )) install_map_templates=$(eval $(call install_map_template,$(1),$(2))) diff --git a/configure b/configure index 01c421d3403840a3c03d249a7ac94bb756f157af..ff350cc3e95d6a6da26ad396b3717dfb32097f2e 100755 --- a/configure +++ b/configure @@ -704,11 +704,13 @@ process_toolchain() { enabled postproc || die "postproc_visualizer requires postproc to be enabled" fi + # Enable WebM IO by default. + soft_enable webm_io + # Enable unit tests by default if we have a working C++ compiler. case "$toolchain" in *-vs*) soft_enable unit_tests - soft_enable webm_io ;; *-android-*) # GTestLog must be modified to use Android logging utilities. @@ -723,22 +725,14 @@ process_toolchain() { # would be disabled for the same reason. check_cxx "$@" <<EOF && soft_enable unit_tests int z; -EOF - check_cxx "$@" <<EOF && soft_enable webm_io -int z; EOF ;; *) enabled pthread_h && check_cxx "$@" <<EOF && soft_enable unit_tests int z; -EOF - check_cxx "$@" <<EOF && soft_enable webm_io -int z; EOF ;; esac - # libwebm needs to be linked with C++ standard library - enabled webm_io && LD=${CXX} } diff --git a/examples.mk b/examples.mk index f091c2de4ad0e7db1a8bd127fb4036a3c3118d6f..87be5a8c924df875dc6e515e4de11f0be9f67af4 100644 --- a/examples.mk +++ b/examples.mk @@ -15,16 +15,6 @@ LIBYUV_SRCS += third_party/libyuv/include/libyuv/basic_types.h \ third_party/libyuv/source/scale.c \ third_party/libyuv/source/cpu_id.c -LIBWEBM_MUXER_SRCS += third_party/libwebm/mkvmuxer.cpp \ - third_party/libwebm/mkvmuxerutil.cpp \ - third_party/libwebm/mkvwriter.cpp \ - third_party/libwebm/mkvmuxer.hpp \ - third_party/libwebm/mkvmuxertypes.hpp \ - third_party/libwebm/mkvmuxerutil.hpp \ - third_party/libwebm/mkvparser.hpp \ - third_party/libwebm/mkvwriter.hpp \ - third_party/libwebm/webmids.hpp - # List of examples to build. UTILS are tools meant for distribution # while EXAMPLES demonstrate specific portions of the API. UTILS-$(CONFIG_DECODERS) += vpxdec.c @@ -63,8 +53,10 @@ vpxenc.SRCS += vpx_ports/vpx_timer.h vpxenc.SRCS += vpxstats.c vpxstats.h vpxenc.SRCS += $(LIBYUV_SRCS) ifeq ($(CONFIG_WEBM_IO),yes) - vpxenc.SRCS += $(LIBWEBM_MUXER_SRCS) - vpxenc.SRCS += webmenc.cc webmenc.h + vpxenc.SRCS += third_party/libmkv/EbmlIDs.h + vpxenc.SRCS += third_party/libmkv/EbmlWriter.c + vpxenc.SRCS += third_party/libmkv/EbmlWriter.h + vpxenc.SRCS += webmenc.c webmenc.h endif vpxenc.GUID = 548DEC74-7A15-4B2B-AFC3-AA102E7C25C1 vpxenc.DESCRIPTION = Full featured encoder diff --git a/vpxenc.c b/vpxenc.c index f1c9c9a7b99878dc46574b3bc7a229ec75d74a75..1cd5e92325233351445d72d8cb5d7effc4101ee0 100644 --- a/vpxenc.c +++ b/vpxenc.c @@ -123,6 +123,55 @@ int fourcc_is_ivf(const char detect[4]) { return 0; } +#if CONFIG_WEBM_IO +/* Murmur hash derived from public domain reference implementation at + * http:// sites.google.com/site/murmurhash/ + */ +static unsigned int murmur(const void *key, int len, unsigned int seed) { + const unsigned int m = 0x5bd1e995; + const int r = 24; + + unsigned int h = seed ^ len; + + const unsigned char *data = (const unsigned char *)key; + + while (len >= 4) { + unsigned int k; + + k = (unsigned int)data[0]; + k |= (unsigned int)data[1] << 8; + k |= (unsigned int)data[2] << 16; + k |= (unsigned int)data[3] << 24; + + k *= m; + k ^= k >> r; + k *= m; + + h *= m; + h ^= k; + + data += 4; + len -= 4; + } + + switch (len) { + case 3: + h ^= data[2] << 16; + case 2: + h ^= data[1] << 8; + case 1: + h ^= data[0]; + h *= m; + }; + + h ^= h >> 13; + h *= m; + h ^= h >> 15; + + return h; +} +#endif // CONFIG_WEBM_IO + static const arg_def_t debugmode = ARG_DEF("D", "debug", 0, "Debug mode (makes output deterministic)"); static const arg_def_t outputfile = ARG_DEF("o", "output", 1, @@ -565,6 +614,7 @@ struct stream_state { FILE *file; struct rate_hist *rate_hist; struct EbmlGlobal ebml; + uint32_t hash; uint64_t psnr_sse_total; uint64_t psnr_samples_total; double psnr_totals[4]; @@ -786,9 +836,7 @@ static struct stream_state *new_stream(struct VpxEncoderConfig *global, stream->config.stereo_fmt = STEREO_FORMAT_MONO; stream->config.write_webm = 1; #if CONFIG_WEBM_IO - stream->ebml.last_pts_ns = -1; - stream->ebml.writer = NULL; - stream->ebml.segment = NULL; + stream->ebml.last_pts_ms = -1; #endif /* Allows removal of the application version from the EBML tags */ @@ -1123,7 +1171,9 @@ static void close_output_file(struct stream_state *stream, #if CONFIG_WEBM_IO if (stream->config.write_webm) { - write_webm_file_footer(&stream->ebml); + write_webm_file_footer(&stream->ebml, stream->hash); + free(stream->ebml.cue_list); + stream->ebml.cue_list = NULL; } #endif @@ -1279,6 +1329,12 @@ static void get_cx_data(struct stream_state *stream, update_rate_histogram(stream->rate_hist, cfg, pkt); #if CONFIG_WEBM_IO if (stream->config.write_webm) { + /* Update the hash */ + if (!stream->ebml.debug) + stream->hash = murmur(pkt->data.frame.buf, + (int)pkt->data.frame.sz, + stream->hash); + write_webm_block(&stream->ebml, cfg, pkt); } #endif diff --git a/webmenc.c b/webmenc.c new file mode 100644 index 0000000000000000000000000000000000000000..17bbeec782949fffe9a7b2669345e9e40e0b9452 --- /dev/null +++ b/webmenc.c @@ -0,0 +1,331 @@ +/* + * Copyright (c) 2013 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 "webmenc.h" + +#include <limits.h> +#include <string.h> + +#include "third_party/libmkv/EbmlWriter.h" +#include "third_party/libmkv/EbmlIDs.h" + +void Ebml_Write(struct EbmlGlobal *glob, + const void *buffer_in, + unsigned long len) { + (void) fwrite(buffer_in, 1, len, glob->stream); +} + +#define WRITE_BUFFER(s) \ +for (i = len - 1; i >= 0; i--) { \ + x = (char)(*(const s *)buffer_in >> (i * CHAR_BIT)); \ + Ebml_Write(glob, &x, 1); \ +} + +void Ebml_Serialize(struct EbmlGlobal *glob, + const void *buffer_in, + int buffer_size, + unsigned long len) { + char x; + int i; + + /* buffer_size: + * 1 - int8_t; + * 2 - int16_t; + * 3 - int32_t; + * 4 - int64_t; + */ + switch (buffer_size) { + case 1: + WRITE_BUFFER(int8_t) + break; + case 2: + WRITE_BUFFER(int16_t) + break; + case 4: + WRITE_BUFFER(int32_t) + break; + case 8: + WRITE_BUFFER(int64_t) + break; + default: + break; + } +} +#undef WRITE_BUFFER + +/* Need a fixed size serializer for the track ID. libmkv provides a 64 bit + * one, but not a 32 bit one. + */ +static void Ebml_SerializeUnsigned32(struct EbmlGlobal *glob, + unsigned int class_id, + uint64_t ui) { + const unsigned char sizeSerialized = 4 | 0x80; + Ebml_WriteID(glob, class_id); + Ebml_Serialize(glob, &sizeSerialized, sizeof(sizeSerialized), 1); + Ebml_Serialize(glob, &ui, sizeof(ui), 4); +} + +static void Ebml_StartSubElement(struct EbmlGlobal *glob, + EbmlLoc *ebmlLoc, + unsigned int class_id) { + const uint64_t kEbmlUnknownLength = LITERALU64(0x01FFFFFF, 0xFFFFFFFF); + Ebml_WriteID(glob, class_id); + *ebmlLoc = ftello(glob->stream); + Ebml_Serialize(glob, &kEbmlUnknownLength, sizeof(kEbmlUnknownLength), 8); +} + +static void Ebml_EndSubElement(struct EbmlGlobal *glob, EbmlLoc *ebmlLoc) { + off_t pos; + uint64_t size; + + /* Save the current stream pointer. */ + pos = ftello(glob->stream); + + /* Calculate the size of this element. */ + size = pos - *ebmlLoc - 8; + size |= LITERALU64(0x01000000, 0x00000000); + + /* Seek back to the beginning of the element and write the new size. */ + fseeko(glob->stream, *ebmlLoc, SEEK_SET); + Ebml_Serialize(glob, &size, sizeof(size), 8); + + /* Reset the stream pointer. */ + fseeko(glob->stream, pos, SEEK_SET); +} + +void write_webm_seek_element(struct EbmlGlobal *ebml, + unsigned int id, + off_t pos) { + uint64_t offset = pos - ebml->position_reference; + EbmlLoc start; + Ebml_StartSubElement(ebml, &start, Seek); + Ebml_SerializeBinary(ebml, SeekID, id); + Ebml_SerializeUnsigned64(ebml, SeekPosition, offset); + Ebml_EndSubElement(ebml, &start); +} + +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 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. */ +} + +void write_webm_block(struct EbmlGlobal *glob, + const vpx_codec_enc_cfg_t *cfg, + const vpx_codec_cx_pkt_t *pkt) { + unsigned int block_length; + unsigned char track_number; + uint16_t block_timecode = 0; + unsigned char flags; + int64_t pts_ms; + int start_cluster = 0, is_keyframe; + + /* Calculate the PTS of this frame in milliseconds. */ + pts_ms = pkt->data.frame.pts * 1000 + * (uint64_t)cfg->g_timebase.num / (uint64_t)cfg->g_timebase.den; + + if (pts_ms <= glob->last_pts_ms) + pts_ms = glob->last_pts_ms + 1; + + glob->last_pts_ms = pts_ms; + + /* Calculate the relative time of this block. */ + if (pts_ms - glob->cluster_timecode > SHRT_MAX) + start_cluster = 1; + else + block_timecode = (uint16_t)pts_ms - glob->cluster_timecode; + + is_keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY); + if (start_cluster || is_keyframe) { + if (glob->cluster_open) + Ebml_EndSubElement(glob, &glob->startCluster); + + /* Open the new cluster. */ + block_timecode = 0; + glob->cluster_open = 1; + glob->cluster_timecode = (uint32_t)pts_ms; + glob->cluster_pos = ftello(glob->stream); + Ebml_StartSubElement(glob, &glob->startCluster, Cluster); + Ebml_SerializeUnsigned(glob, Timecode, glob->cluster_timecode); + + /* Save a cue point if this is a keyframe. */ + if (is_keyframe) { + struct cue_entry *cue, *new_cue_list; + + new_cue_list = realloc(glob->cue_list, + (glob->cues + 1) * sizeof(struct cue_entry)); + if (new_cue_list) + glob->cue_list = new_cue_list; + else + fatal("Failed to realloc cue list."); + + cue = &glob->cue_list[glob->cues]; + cue->time = glob->cluster_timecode; + cue->loc = glob->cluster_pos; + glob->cues++; + } + } + + /* Write the Simple Block. */ + Ebml_WriteID(glob, SimpleBlock); + + block_length = (unsigned int)pkt->data.frame.sz + 4; + block_length |= 0x10000000; + Ebml_Serialize(glob, &block_length, sizeof(block_length), 4); + + track_number = 1; + track_number |= 0x80; + Ebml_Write(glob, &track_number, 1); + + Ebml_Serialize(glob, &block_timecode, sizeof(block_timecode), 2); + + flags = 0; + if (is_keyframe) + flags |= 0x80; + if (pkt->data.frame.flags & VPX_FRAME_IS_INVISIBLE) + flags |= 0x08; + Ebml_Write(glob, &flags, 1); + + Ebml_Write(glob, pkt->data.frame.buf, (unsigned int)pkt->data.frame.sz); +} + +void write_webm_file_footer(struct EbmlGlobal *glob, int hash) { + EbmlLoc start_cues; + EbmlLoc start_cue_point; + EbmlLoc start_cue_tracks; + unsigned int i; + + if (glob->cluster_open) + Ebml_EndSubElement(glob, &glob->startCluster); + + glob->cue_pos = ftello(glob->stream); + Ebml_StartSubElement(glob, &start_cues, Cues); + + for (i = 0; i < glob->cues; i++) { + struct cue_entry *cue = &glob->cue_list[i]; + Ebml_StartSubElement(glob, &start_cue_point, CuePoint); + Ebml_SerializeUnsigned(glob, CueTime, cue->time); + + Ebml_StartSubElement(glob, &start_cue_tracks, CueTrackPositions); + Ebml_SerializeUnsigned(glob, CueTrack, 1); + Ebml_SerializeUnsigned64(glob, CueClusterPosition, + cue->loc - glob->position_reference); + Ebml_EndSubElement(glob, &start_cue_tracks); + + Ebml_EndSubElement(glob, &start_cue_point); + } + + Ebml_EndSubElement(glob, &start_cues); + + /* Close the Segment. */ + Ebml_EndSubElement(glob, &glob->startSegment); + + /* Patch up the seek info block. */ + write_webm_seek_info(glob); + + /* Patch up the track id. */ + fseeko(glob->stream, glob->track_id_pos, SEEK_SET); + Ebml_SerializeUnsigned32(glob, TrackUID, glob->debug ? 0xDEADBEEF : hash); + + fseeko(glob->stream, 0, SEEK_END); +} diff --git a/webmenc.cc b/webmenc.cc deleted file mode 100644 index 6a3374d029e32b990ef39dd12ef18f6bc06aa2d9..0000000000000000000000000000000000000000 --- a/webmenc.cc +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2014 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 "./webmenc.h" - -#include <string> - -#include "third_party/libwebm/mkvmuxer.hpp" -#include "third_party/libwebm/mkvmuxerutil.hpp" -#include "third_party/libwebm/mkvwriter.hpp" - -namespace { -const uint64_t kDebugTrackUid = 0xDEADBEEF; -const int kVideoTrackNumber = 1; -} // namespace - -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) { - mkvmuxer::MkvWriter *const writer = new mkvmuxer::MkvWriter(glob->stream); - mkvmuxer::Segment *const segment = new mkvmuxer::Segment(); - segment->Init(writer); - segment->set_mode(mkvmuxer::Segment::kFile); - segment->OutputCues(true); - - mkvmuxer::SegmentInfo *const info = segment->GetSegmentInfo(); - const uint64_t kTimecodeScale = 1000000; - info->set_timecode_scale(kTimecodeScale); - std::string version = "vpxenc"; - if (!glob->debug) { - version.append(std::string(" ") + vpx_codec_version_str()); - } - info->set_writing_app(version.c_str()); - - const int video_track_id = segment->AddVideoTrack(static_cast<int>(cfg->g_w), - static_cast<int>(cfg->g_h), - kVideoTrackNumber); - mkvmuxer::VideoTrack* const video_track = - static_cast<mkvmuxer::VideoTrack*>( - segment->GetTrackByNumber(video_track_id)); - video_track->SetStereoMode(stereo_fmt); - video_track->set_codec_id(fourcc == VP8_FOURCC ? "V_VP8" : "V_VP9"); - if (glob->debug) { - video_track->set_uid(kDebugTrackUid); - } - glob->writer = writer; - glob->segment = segment; -} - -void write_webm_block(struct EbmlGlobal *glob, - const vpx_codec_enc_cfg_t *cfg, - const vpx_codec_cx_pkt_t *pkt) { - mkvmuxer::Segment *const segment = - reinterpret_cast<mkvmuxer::Segment*>(glob->segment); - int64_t pts_ns = pkt->data.frame.pts * 1000000000ll * - cfg->g_timebase.num / cfg->g_timebase.den; - if (pts_ns <= glob->last_pts_ns) - pts_ns = glob->last_pts_ns + 1000000; - glob->last_pts_ns = pts_ns; - - segment->AddFrame(static_cast<uint8_t*>(pkt->data.frame.buf), - pkt->data.frame.sz, - kVideoTrackNumber, - pts_ns, - pkt->data.frame.flags & VPX_FRAME_IS_KEY); -} - -void write_webm_file_footer(struct EbmlGlobal *glob) { - mkvmuxer::MkvWriter *const writer = - reinterpret_cast<mkvmuxer::MkvWriter*>(glob->writer); - mkvmuxer::Segment *const segment = - reinterpret_cast<mkvmuxer::Segment*>(glob->segment); - segment->Finalize(); - delete segment; - delete writer; - glob->writer = NULL; - glob->segment = NULL; -} diff --git a/webmenc.h b/webmenc.h index 0ac606be4831e4955ab63c42e8bf4cbc5445458e..362aa895fb03cdfbf0f5fd4fb6283aef2fba1b1f 100644 --- a/webmenc.h +++ b/webmenc.h @@ -13,6 +13,13 @@ #include <stdio.h> #include <stdlib.h> +#if defined(_MSC_VER) +/* MSVS doesn't define off_t */ +typedef __int64 off_t; +#else +#include <stdint.h> +#endif + #include "tools_common.h" #include "vpx/vpx_encoder.h" @@ -20,13 +27,40 @@ extern "C" { #endif -/* TODO(vigneshv): Rename this struct */ +typedef off_t EbmlLoc; + +struct cue_entry { + unsigned int time; + uint64_t loc; +}; + struct EbmlGlobal { int debug; + FILE *stream; - int64_t last_pts_ns; - void *writer; - void *segment; + int64_t last_pts_ms; + vpx_rational_t framerate; + + /* These pointers are to the start of an element */ + off_t position_reference; + off_t seek_info_pos; + off_t segment_info_pos; + off_t track_pos; + off_t cue_pos; + off_t cluster_pos; + + /* This pointer is to a specific element to be serialized */ + off_t track_id_pos; + + /* These pointers are to the size field of the element */ + EbmlLoc startSegment; + EbmlLoc startCluster; + + uint32_t cluster_timecode; + int cluster_open; + + struct cue_entry *cue_list; + unsigned int cues; }; /* Stereo 3D packed frame format */ @@ -38,6 +72,10 @@ typedef enum stereo_format { STEREO_FORMAT_RIGHT_LEFT = 11 } stereo_format_t; +void write_webm_seek_element(struct EbmlGlobal *ebml, + unsigned int id, + off_t pos); + void write_webm_file_header(struct EbmlGlobal *glob, const vpx_codec_enc_cfg_t *cfg, const struct vpx_rational *fps, @@ -48,7 +86,7 @@ void write_webm_block(struct EbmlGlobal *glob, const vpx_codec_enc_cfg_t *cfg, const vpx_codec_cx_pkt_t *pkt); -void write_webm_file_footer(struct EbmlGlobal *glob); +void write_webm_file_footer(struct EbmlGlobal *glob, int hash); #ifdef __cplusplus } // extern "C"