Merge "Revert "Changing webmenc to use libwebm""
This commit is contained in:
commit
dc510b59b8
@ -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)))
|
||||
|
12
configure
vendored
12
configure
vendored
@ -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}
|
||||
}
|
||||
|
||||
|
||||
|
16
examples.mk
16
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
|
||||
|
64
vpxenc.c
64
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
|
||||
|
331
webmenc.c
Normal file
331
webmenc.c
Normal file
@ -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);
|
||||
}
|
86
webmenc.cc
86
webmenc.cc
@ -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;
|
||||
}
|
48
webmenc.h
48
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"
|
||||
|
Loading…
Reference in New Issue
Block a user