Merge b2g-inbound to m-c.

This commit is contained in:
Ryan VanderMeulen 2014-01-27 15:05:03 -05:00
commit c35da6fdf3
49 changed files with 2970 additions and 43 deletions

View File

@ -12,7 +12,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="75ea7d07cdb590722634016410e12819faf82e5a"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="6586d2b8b43c6997be5cf5895bbdf3dd20490725"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eda08beb3ba9a159843c70ffde0f9660ec351eb9"/>

View File

@ -11,7 +11,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="75ea7d07cdb590722634016410e12819faf82e5a"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="6586d2b8b43c6997be5cf5895bbdf3dd20490725"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="96d2d00165f4561fbde62d1062706eab74b3a01f"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="a887bfabaed83c4588b40c845535c0388c8da0f3"/>
@ -24,6 +24,7 @@
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
<project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
<project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="1342fd7b4b000ac3e76a5dfe111a0de9d710b4c8"/>
<project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="1b26ad444462ccbd97f6319565b4735f7bd779e5"/>
<project name="device/common" path="device/common" revision="4e1a38704dcfadef60ed2da3cfeba02a56b069d2"/>
<project name="device/sample" path="device/sample" revision="b045905b46c8b4ee630d0c2aee7db63eaec722d9"/>
<project name="platform/abi/cpp" path="abi/cpp" revision="fa873799be5cf200f1d1d32a63953949c9dcdda8"/>

View File

@ -12,7 +12,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="75ea7d07cdb590722634016410e12819faf82e5a"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="6586d2b8b43c6997be5cf5895bbdf3dd20490725"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eda08beb3ba9a159843c70ffde0f9660ec351eb9"/>

View File

@ -1,4 +1,4 @@
{
"revision": "c5f8db7e1e71a9bfe0d29665d2b4cf3ae773094e",
"revision": "1150c11d1e6f0f78df3552dfca8c53d5ed5c173d",
"repo_path": "/integration/gaia-central"
}

View File

@ -11,7 +11,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="75ea7d07cdb590722634016410e12819faf82e5a"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="6586d2b8b43c6997be5cf5895bbdf3dd20490725"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>

View File

@ -10,7 +10,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="75ea7d07cdb590722634016410e12819faf82e5a"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="6586d2b8b43c6997be5cf5895bbdf3dd20490725"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>

View File

@ -12,7 +12,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="75ea7d07cdb590722634016410e12819faf82e5a"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="6586d2b8b43c6997be5cf5895bbdf3dd20490725"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>

View File

@ -11,7 +11,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="75ea7d07cdb590722634016410e12819faf82e5a"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="6586d2b8b43c6997be5cf5895bbdf3dd20490725"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>

View File

@ -11,7 +11,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="75ea7d07cdb590722634016410e12819faf82e5a"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="6586d2b8b43c6997be5cf5895bbdf3dd20490725"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="96d2d00165f4561fbde62d1062706eab74b3a01f"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="a887bfabaed83c4588b40c845535c0388c8da0f3"/>
@ -24,6 +24,7 @@
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
<project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
<project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="1342fd7b4b000ac3e76a5dfe111a0de9d710b4c8"/>
<project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="1b26ad444462ccbd97f6319565b4735f7bd779e5"/>
<project name="device/common" path="device/common" revision="4e1a38704dcfadef60ed2da3cfeba02a56b069d2"/>
<project name="device/sample" path="device/sample" revision="b045905b46c8b4ee630d0c2aee7db63eaec722d9"/>
<project name="platform/abi/cpp" path="abi/cpp" revision="fa873799be5cf200f1d1d32a63953949c9dcdda8"/>

View File

@ -11,7 +11,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="75ea7d07cdb590722634016410e12819faf82e5a"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="6586d2b8b43c6997be5cf5895bbdf3dd20490725"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>

View File

@ -64,6 +64,7 @@ MOZ_PAY=1
# Enable activities. These are used for FxOS developers currently.
MOZ_ACTIVITIES=1
MOZ_JSDOWNLOADS=1
MOZ_WEBM_ENCODER=1
# Enable exact rooting on desktop.
JSGC_USE_EXACT_ROOTING=1

View File

@ -27,6 +27,9 @@ if CONFIG['MOZ_OPUS']:
if CONFIG['MOZ_WEBM']:
external_dirs += ['media/libnestegg']
if CONFIG['MOZ_WEBM_ENCODER']:
external_dirs += ['media/libmkv']
if CONFIG['MOZ_VPX'] and not CONFIG['MOZ_NATIVE_LIBVPX']:
external_dirs += ['media/libvpx']

View File

@ -5546,6 +5546,11 @@ if test -n "$MOZ_OPUS"; then
AC_DEFINE(MOZ_OPUS)
fi
if test -n "$MOZ_WEBM_ENCODER"; then
AC_DEFINE(MOZ_WEBM_ENCODER)
fi
AC_SUBST(MOZ_WEBM_ENCODER)
dnl ==================================
dnl = Check alsa availability on Linux
dnl ==================================

View File

@ -230,18 +230,20 @@ public:
nsContentUtils::UnregisterShutdownObserver(this);
}
void Pause()
nsresult Pause()
{
MOZ_ASSERT(NS_IsMainThread() && mTrackUnionStream);
NS_ENSURE_TRUE(NS_IsMainThread() && mTrackUnionStream, NS_ERROR_FAILURE);
mTrackUnionStream->ChangeExplicitBlockerCount(-1);
return NS_OK;
}
void Resume()
nsresult Resume()
{
MOZ_ASSERT(NS_IsMainThread() && mTrackUnionStream);
NS_ENSURE_TRUE(NS_IsMainThread() && mTrackUnionStream, NS_ERROR_FAILURE);
mTrackUnionStream->ChangeExplicitBlockerCount(1);
return NS_OK;
}
already_AddRefed<nsIDOMBlob> GetEncodedData()
@ -499,11 +501,13 @@ MediaRecorder::Pause(ErrorResult& aResult)
return;
}
mState = RecordingState::Paused;
MOZ_ASSERT(mSession != nullptr);
if (mSession) {
mSession->Pause();
nsresult rv = mSession->Pause();
if (NS_FAILED(rv)) {
NotifyError(rv);
return;
}
mState = RecordingState::Paused;
}
}
@ -518,7 +522,11 @@ MediaRecorder::Resume(ErrorResult& aResult)
MOZ_ASSERT(mSession != nullptr);
if (mSession) {
mSession->Resume();
nsresult rv = mSession->Resume();
if (NS_FAILED(rv)) {
NotifyError(rv);
return;
}
mState = RecordingState::Recording;
}
}

View File

@ -14,6 +14,11 @@
#endif
#ifdef MOZ_OPUS
#include "OpusTrackEncoder.h"
#endif
#ifdef MOZ_VORBIS
#include "VorbisTrackEncoder.h"
#endif
#ifdef MOZ_WEBM_ENCODER
#include "VorbisTrackEncoder.h"

View File

@ -128,6 +128,20 @@ AudioTrackEncoder::InterleaveTrackData(AudioChunk& aChunk,
}
}
/*static*/
void
AudioTrackEncoder::DeInterleaveTrackData(AudioDataValue* aInput,
int32_t aDuration,
int32_t aChannels,
AudioDataValue* aOutput)
{
for (int32_t i = 0; i < aChannels; ++i) {
for(int32_t j = 0; j < aDuration; ++j) {
aOutput[i * aDuration + j] = aInput[i + j * aChannels];
}
}
}
void
VideoTrackEncoder::NotifyQueuedTrackChanges(MediaStreamGraph* aGraph,
TrackID aID,

View File

@ -158,6 +158,13 @@ public:
uint32_t aOutputChannels,
AudioDataValue* aOutput);
/**
* De-interleaves the aInput data and stores the result into aOutput.
* No up-mix or down-mix operations inside.
*/
static void DeInterleaveTrackData(AudioDataValue* aInput, int32_t aDuration,
int32_t aChannels, AudioDataValue* aOutput);
protected:
/**
* Number of samples per channel in a pcm buffer. This is also the value of

View File

@ -18,6 +18,7 @@ public:
enum MetadataKind {
METADATA_OPUS, // Represent the Opus metadata
METADATA_VP8,
METADATA_VORBIS,
METADATA_AVC,
METADATA_AAC,
METADATA_UNKNOWN // Metadata Kind not set

View File

@ -0,0 +1,472 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "VP8TrackEncoder.h"
#include "vpx/vp8cx.h"
#include "vpx/vpx_encoder.h"
#include "VideoUtils.h"
#include "prsystem.h"
#include "WebMWriter.h"
namespace mozilla {
#ifdef PR_LOGGING
PRLogModuleInfo* gVP8TrackEncoderLog;
#define VP8LOG(msg, ...) PR_LOG(gVP8TrackEncoderLog, PR_LOG_DEBUG, \
(msg, ##__VA_ARGS__))
// Debug logging macro with object pointer and class name.
#else
#define VP8LOG(msg, ...)
#endif
#define DEFAULT_BITRATE 2500 // in kbit/s
#define DEFAULT_ENCODE_FRAMERATE 30
VP8TrackEncoder::VP8TrackEncoder()
: VideoTrackEncoder()
, mEncodedFrameDuration(0)
, mEncodedTimestamp(0)
, mRemainingTicks(0)
, mVPXContext(new vpx_codec_ctx_t())
, mVPXImageWrapper(new vpx_image_t())
{
MOZ_COUNT_CTOR(VP8TrackEncoder);
#ifdef PR_LOGGING
if (!gVP8TrackEncoderLog) {
gVP8TrackEncoderLog = PR_NewLogModule("VP8TrackEncoder");
}
#endif
}
VP8TrackEncoder::~VP8TrackEncoder()
{
if (mInitialized) {
vpx_codec_destroy(mVPXContext);
}
if (mVPXImageWrapper) {
vpx_img_free(mVPXImageWrapper);
}
MOZ_COUNT_DTOR(VP8TrackEncoder);
}
nsresult
VP8TrackEncoder::Init(int32_t aWidth, int32_t aHeight, TrackRate aTrackRate)
{
if (aWidth < 1 || aHeight < 1 || aTrackRate <= 0) {
return NS_ERROR_FAILURE;
}
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
mTrackRate = aTrackRate;
mEncodedFrameRate = DEFAULT_ENCODE_FRAMERATE;
mEncodedFrameDuration = mTrackRate / mEncodedFrameRate;
mFrameWidth = aWidth;
mFrameHeight = aHeight;
// Encoder configuration structure.
vpx_codec_enc_cfg_t config;
memset(&config, 0, sizeof(vpx_codec_enc_cfg_t));
if (vpx_codec_enc_config_default(vpx_codec_vp8_cx(), &config, 0)) {
return NS_ERROR_FAILURE;
}
// Creating a wrapper to the image - setting image data to NULL. Actual
// pointer will be set in encode. Setting align to 1, as it is meaningless
// (actual memory is not allocated).
vpx_img_wrap(mVPXImageWrapper, IMG_FMT_I420,
mFrameWidth, mFrameHeight, 1, nullptr);
config.g_w = mFrameWidth;
config.g_h = mFrameHeight;
// TODO: Maybe we should have various aFrameRate bitrate pair for each devices?
// or for different platform
config.rc_target_bitrate = DEFAULT_BITRATE; // in kbit/s
// Setting the time base of the codec
config.g_timebase.num = 1;
config.g_timebase.den = mTrackRate;
config.g_error_resilient = 0;
config.g_lag_in_frames = 0; // 0- no frame lagging
int32_t number_of_cores = PR_GetNumberOfProcessors();
if (mFrameWidth * mFrameHeight > 1280 * 960 && number_of_cores >= 6) {
config.g_threads = 3; // 3 threads for 1080p.
} else if (mFrameWidth * mFrameHeight > 640 * 480 && number_of_cores >= 3) {
config.g_threads = 2; // 2 threads for qHD/HD.
} else {
config.g_threads = 1; // 1 thread for VGA or less
}
// rate control settings
config.rc_dropframe_thresh = 0;
config.rc_end_usage = VPX_CBR;
config.g_pass = VPX_RC_ONE_PASS;
config.rc_resize_allowed = 1;
config.rc_undershoot_pct = 100;
config.rc_overshoot_pct = 15;
config.rc_buf_initial_sz = 500;
config.rc_buf_optimal_sz = 600;
config.rc_buf_sz = 1000;
config.kf_mode = VPX_KF_AUTO;
// Ensure that we can output one I-frame per second.
config.kf_max_dist = mEncodedFrameRate;
vpx_codec_flags_t flags = 0;
flags |= VPX_CODEC_USE_OUTPUT_PARTITION;
if (vpx_codec_enc_init(mVPXContext, vpx_codec_vp8_cx(), &config, flags)) {
return NS_ERROR_FAILURE;
}
vpx_codec_control(mVPXContext, VP8E_SET_STATIC_THRESHOLD, 1);
vpx_codec_control(mVPXContext, VP8E_SET_CPUUSED, -6);
vpx_codec_control(mVPXContext, VP8E_SET_TOKEN_PARTITIONS,
VP8_ONE_TOKENPARTITION);
mInitialized = true;
mon.NotifyAll();
return NS_OK;
}
already_AddRefed<TrackMetadataBase>
VP8TrackEncoder::GetMetadata()
{
{
// Wait if mEncoder is not initialized.
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
while (!mCanceled && !mInitialized) {
mon.Wait();
}
}
if (mCanceled || mEncodingComplete) {
return nullptr;
}
nsRefPtr<VP8Metadata> meta = new VP8Metadata();
meta->mWidth = mFrameWidth;
meta->mHeight = mFrameHeight;
meta->mEncodedFrameRate = mEncodedFrameRate;
return meta.forget();
}
nsresult
VP8TrackEncoder::GetEncodedPartitions(EncodedFrameContainer& aData)
{
vpx_codec_iter_t iter = nullptr;
EncodedFrame::FrameType frameType = EncodedFrame::P_FRAME;
nsTArray<uint8_t> frameData;
const vpx_codec_cx_pkt_t *pkt = nullptr;
while ((pkt = vpx_codec_get_cx_data(mVPXContext, &iter)) != nullptr) {
switch (pkt->kind) {
case VPX_CODEC_CX_FRAME_PKT: {
// Copy the encoded data from libvpx to frameData
frameData.AppendElements((uint8_t*)pkt->data.frame.buf,
pkt->data.frame.sz);
break;
}
default: {
break;
}
}
// End of frame
if ((pkt->data.frame.flags & VPX_FRAME_IS_FRAGMENT) == 0) {
if (pkt->data.frame.flags & VPX_FRAME_IS_KEY) {
frameType = EncodedFrame::I_FRAME;
}
break;
}
}
if (!frameData.IsEmpty() &&
(pkt->data.frame.pts == mEncodedTimestamp)) {
// Copy the encoded data to aData.
EncodedFrame* videoData = new EncodedFrame();
videoData->SetFrameType(frameType);
// Convert the timestamp and duration to Usecs.
CheckedInt64 timestamp = FramesToUsecs(mEncodedTimestamp, mTrackRate);
if (timestamp.isValid()) {
videoData->SetTimeStamp(
(uint64_t)FramesToUsecs(mEncodedTimestamp, mTrackRate).value());
}
CheckedInt64 duration = FramesToUsecs(pkt->data.frame.duration, mTrackRate);
if (duration.isValid()) {
videoData->SetDuration(
(uint64_t)FramesToUsecs(pkt->data.frame.duration, mTrackRate).value());
}
videoData->SetFrameData(&frameData);
VP8LOG("GetEncodedPartitions TimeStamp %lld Duration %lld\n",
videoData->GetTimeStamp(), videoData->GetDuration());
VP8LOG("frameType %d\n", videoData->GetFrameType());
aData.AppendEncodedFrame(videoData);
}
return NS_OK;
}
void VP8TrackEncoder::PrepareMutedFrame()
{
if (mMuteFrame.IsEmpty()) {
CreateMutedFrame(&mMuteFrame);
}
uint32_t yPlanSize = mFrameWidth * mFrameHeight;
uint32_t halfWidth = (mFrameWidth + 1) / 2;
uint32_t halfHeight = (mFrameHeight + 1) / 2;
uint32_t uvPlanSize = halfWidth * halfHeight;
MOZ_ASSERT(mMuteFrame.Length() >= (yPlanSize + uvPlanSize));
uint8_t *y = mMuteFrame.Elements();
uint8_t *cb = mMuteFrame.Elements() + yPlanSize;
uint8_t *cr = mMuteFrame.Elements() + yPlanSize + uvPlanSize;
mVPXImageWrapper->planes[PLANE_Y] = y;
mVPXImageWrapper->planes[PLANE_U] = cb;
mVPXImageWrapper->planes[PLANE_V] = cr;
mVPXImageWrapper->stride[VPX_PLANE_Y] = mFrameWidth;
mVPXImageWrapper->stride[VPX_PLANE_U] = halfWidth;
mVPXImageWrapper->stride[VPX_PLANE_V] = halfWidth;
}
nsresult VP8TrackEncoder::PrepareRawFrame(VideoChunk &aChunk)
{
if (aChunk.mFrame.GetForceBlack()) {
PrepareMutedFrame();
} else {
layers::Image* img = aChunk.mFrame.GetImage();
if (NS_WARN_IF(!img)) {
return NS_ERROR_NULL_POINTER;
}
ImageFormat format = img->GetFormat();
if (format != PLANAR_YCBCR) {
VP8LOG("Unsupported video format\n");
return NS_ERROR_FAILURE;
}
// Cast away constness b/c some of the accessors are non-const
layers::PlanarYCbCrImage* yuv =
const_cast<layers::PlanarYCbCrImage *>(static_cast<const layers::PlanarYCbCrImage *>(img));
// Big-time assumption here that this is all contiguous data coming
// from getUserMedia or other sources.
MOZ_ASSERT(yuv);
const layers::PlanarYCbCrImage::Data *data = yuv->GetData();
mVPXImageWrapper->planes[PLANE_Y] = data->mYChannel;
mVPXImageWrapper->planes[PLANE_U] = data->mCbChannel;
mVPXImageWrapper->planes[PLANE_V] = data->mCrChannel;
mVPXImageWrapper->stride[VPX_PLANE_Y] = data->mYStride;
mVPXImageWrapper->stride[VPX_PLANE_U] = data->mCbCrStride;
mVPXImageWrapper->stride[VPX_PLANE_V] = data->mCbCrStride;
}
return NS_OK;
}
// These two define value used in GetNextEncodeOperation to determine the
// EncodeOperation for next target frame.
#define I_FRAME_RATIO (0.5)
#define SKIP_FRAME_RATIO (0.75)
/**
* Compares the elapsed time from the beginning of GetEncodedTrack and
* the processed frame duration in mSourceSegment
* in order to set the nextEncodeOperation for next target frame.
*/
VP8TrackEncoder::EncodeOperation
VP8TrackEncoder::GetNextEncodeOperation(TimeDuration aTimeElapsed,
TrackTicks aProcessedDuration)
{
int64_t durationInUsec =
FramesToUsecs(aProcessedDuration + mEncodedFrameDuration,
mTrackRate).value();
if (aTimeElapsed.ToMicroseconds() > (durationInUsec * SKIP_FRAME_RATIO)) {
// The encoder is too slow.
// We should skip next frame to consume the mSourceSegment.
return SKIP_FRAME;
} else if (aTimeElapsed.ToMicroseconds() > (durationInUsec * I_FRAME_RATIO)) {
// The encoder is a little slow.
// We force the encoder to encode an I-frame to accelerate.
return ENCODE_I_FRAME;
} else {
return ENCODE_NORMAL_FRAME;
}
}
TrackTicks
VP8TrackEncoder::CalculateRemainingTicks(TrackTicks aDurationCopied,
TrackTicks aEncodedDuration)
{
return mRemainingTicks + aEncodedDuration - aDurationCopied;
}
// Try to extend the encodedDuration as long as possible if the target frame
// has a long duration.
TrackTicks
VP8TrackEncoder::CalculateEncodedDuration(TrackTicks aDurationCopied)
{
TrackTicks temp64 = aDurationCopied;
TrackTicks encodedDuration = mEncodedFrameDuration;
temp64 -= mRemainingTicks;
while (temp64 > mEncodedFrameDuration) {
temp64 -= mEncodedFrameDuration;
encodedDuration += mEncodedFrameDuration;
}
return encodedDuration;
}
/**
* Encoding flow in GetEncodedTrack():
* 1: Check the mInitialized state and the packet duration.
* 2: Move the data from mRawSegment to mSourceSegment.
* 3: Encode the video chunks in mSourceSegment in a for-loop.
* 3.1: Pick the video chunk by mRemainingTicks.
* 3.2: Calculate the encoding duration for the parameter of vpx_codec_encode().
* The encoding duration is a multiple of mEncodedFrameDuration.
* 3.3: Setup the video chunk to mVPXImageWrapper by PrepareRawFrame().
* 3.4: Send frame into vp8 encoder by vpx_codec_encode().
* 3.5: Get the output frame from encoder by calling GetEncodedPartitions().
* 3.6: Calculate the mRemainingTicks for next target frame.
* 3.7: Set the nextEncodeOperation for the next target frame.
* There is a heuristic: If the frame duration we have processed in
* mSourceSegment is 100ms, means that we can't spend more than 100ms to
* encode it.
* 4. Remove the encoded chunks in mSourceSegment after for-loop.
*
* Ex1: Input frame rate is 100 => input frame duration is 10ms for each.
* mEncodedFrameRate is 30 => output frame duration is 33ms.
* In this case, the frame duration in mSourceSegment will be:
* 1st : 0~10ms
* 2nd : 10~20ms
* 3rd : 20~30ms
* 4th : 30~40ms
* ...
* The VP8 encoder will take the 1st and 4th frames to encode. At beginning
* mRemainingTicks is 0 for 1st frame, then the mRemainingTicks is set
* to 23 to pick the 4th frame. (mEncodedFrameDuration - 1st frame duration)
*
* Ex2: Input frame rate is 25 => frame duration is 40ms for each.
* mEncodedFrameRate is 30 => output frame duration is 33ms.
* In this case, the frame duration in mSourceSegment will be:
* 1st : 0~40ms
* 2nd : 40~80ms
* 3rd : 80~120ms
* 4th : 120~160ms
* ...
* Because the input frame duration is 40ms larger than 33ms, so the first
* encoded frame duration will be 66ms by calling CalculateEncodedDuration.
* And the mRemainingTicks will be set to 26
* (CalculateRemainingTicks 0+66-40) in order to pick the next frame(2nd)
* in mSourceSegment.
*/
nsresult
VP8TrackEncoder::GetEncodedTrack(EncodedFrameContainer& aData)
{
{
// Move all the samples from mRawSegment to mSourceSegment. We only hold
// the monitor in this block.
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
// Wait if mEncoder is not initialized, or when not enough raw data, but is
// not the end of stream nor is being canceled.
while (!mCanceled && (!mInitialized ||
(mRawSegment.GetDuration() + mSourceSegment.GetDuration() <
mEncodedFrameDuration && !mEndOfStream))) {
mon.Wait();
}
if (mCanceled || mEncodingComplete) {
return NS_ERROR_FAILURE;
}
mSourceSegment.AppendFrom(&mRawSegment);
}
VideoSegment::ChunkIterator iter(mSourceSegment);
TrackTicks durationCopied = 0;
TrackTicks totalProcessedDuration = 0;
TimeStamp timebase = TimeStamp::Now();
EncodeOperation nextEncodeOperation = ENCODE_NORMAL_FRAME;
for (; !iter.IsEnded(); iter.Next()) {
VideoChunk &chunk = *iter;
// Accumulate chunk's duration to durationCopied until it reaches
// mRemainingTicks.
durationCopied += chunk.GetDuration();
MOZ_ASSERT(mRemainingTicks <= mEncodedFrameDuration);
VP8LOG("durationCopied %lld mRemainingTicks %lld\n",
durationCopied, mRemainingTicks);
if (durationCopied >= mRemainingTicks) {
VP8LOG("nextEncodeOperation is %d\n",nextEncodeOperation);
// Calculate encodedDuration for this target frame.
TrackTicks encodedDuration = CalculateEncodedDuration(durationCopied);
// Encode frame.
if (nextEncodeOperation != SKIP_FRAME) {
nsresult rv = PrepareRawFrame(chunk);
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
// Encode the data with VP8 encoder
int flags = (nextEncodeOperation == ENCODE_NORMAL_FRAME) ?
0 : VPX_EFLAG_FORCE_KF;
if (vpx_codec_encode(mVPXContext, mVPXImageWrapper, mEncodedTimestamp,
(unsigned long)encodedDuration, flags,
VPX_DL_REALTIME)) {
return NS_ERROR_FAILURE;
}
// Get the encoded data from VP8 encoder.
GetEncodedPartitions(aData);
} else {
// SKIP_FRAME
// Extend the duration of the last encoded data in aData
// because this frame will be skip.
nsRefPtr<EncodedFrame> last = nullptr;
last = aData.GetEncodedFrames().LastElement();
if (last) {
last->SetDuration(last->GetDuration() + encodedDuration);
}
}
// Move forward the mEncodedTimestamp.
mEncodedTimestamp += encodedDuration;
totalProcessedDuration += durationCopied;
// Calculate mRemainingTicks for next target frame.
mRemainingTicks = CalculateRemainingTicks(durationCopied,
encodedDuration);
// Check the remain data is enough for next target frame.
if (mSourceSegment.GetDuration() - totalProcessedDuration
>= mEncodedFrameDuration) {
TimeDuration elapsedTime = TimeStamp::Now() - timebase;
nextEncodeOperation = GetNextEncodeOperation(elapsedTime,
totalProcessedDuration);
// Reset durationCopied for next iteration.
durationCopied = 0;
} else {
// Process done, there is no enough data left for next iteration,
// break the for-loop.
break;
}
}
}
// Remove the chunks we have processed.
mSourceSegment.RemoveLeading(totalProcessedDuration);
VP8LOG("RemoveLeading %lld\n",totalProcessedDuration);
// End of stream, pull the rest frames in encoder.
if (mEndOfStream) {
VP8LOG("mEndOfStream is true\n");
mEncodingComplete = true;
if (vpx_codec_encode(mVPXContext, nullptr, mEncodedTimestamp,
mEncodedFrameDuration, 0, VPX_DL_REALTIME)) {
return NS_ERROR_FAILURE;
}
GetEncodedPartitions(aData);
}
return NS_OK ;
}
} // namespace mozilla

View File

@ -0,0 +1,93 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef VP8TrackEncoder_h_
#define VP8TrackEncoder_h_
#include "TrackEncoder.h"
#include "vpx/vpx_codec.h"
namespace mozilla {
typedef struct vpx_codec_ctx vpx_codec_ctx_t;
typedef struct vpx_codec_enc_cfg vpx_codec_enc_cfg_t;
typedef struct vpx_image vpx_image_t;
/**
* VP8TrackEncoder implements VideoTrackEncoder by using libvpx library.
* We implement a realtime and fixed FPS encoder. In order to achieve that,
* there is a pick target frame and drop frame encoding policy implemented in
* GetEncodedTrack.
*/
class VP8TrackEncoder : public VideoTrackEncoder
{
enum EncodeOperation {
ENCODE_NORMAL_FRAME, // VP8 track encoder works normally.
ENCODE_I_FRAME, // The next frame will be encoded as I-Frame.
SKIP_FRAME, // Skip the next frame.
};
public:
VP8TrackEncoder();
virtual ~VP8TrackEncoder();
already_AddRefed<TrackMetadataBase> GetMetadata() MOZ_FINAL MOZ_OVERRIDE;
nsresult GetEncodedTrack(EncodedFrameContainer& aData) MOZ_FINAL MOZ_OVERRIDE;
protected:
nsresult Init(int32_t aWidth, int32_t aHeight,
TrackRate aTrackRate) MOZ_FINAL MOZ_OVERRIDE;
private:
// Calculate the target frame's encoded duration.
TrackTicks CalculateEncodedDuration(TrackTicks aDurationCopied);
// Calculate the mRemainingTicks for next target frame.
TrackTicks CalculateRemainingTicks(TrackTicks aDurationCopied,
TrackTicks aEncodedDuration);
// Get the EncodeOperation for next target frame.
EncodeOperation GetNextEncodeOperation(TimeDuration aTimeElapsed,
TrackTicks aProcessedDuration);
// Get the encoded data from encoder to aData.
nsresult GetEncodedPartitions(EncodedFrameContainer& aData);
// Prepare the input data to the mVPXImageWrapper for encoding.
nsresult PrepareRawFrame(VideoChunk &aChunk);
// Prepare the muted frame data to the mVPXImageWrapper for encoding.
void PrepareMutedFrame();
// Output frame rate.
uint32_t mEncodedFrameRate;
// Duration for the output frame, reciprocal to mEncodedFrameRate.
TrackTicks mEncodedFrameDuration;
// Encoded timestamp.
TrackTicks mEncodedTimestamp;
// Duration to the next encode frame.
TrackTicks mRemainingTicks;
// Muted frame, we only create it once.
nsTArray<uint8_t> mMuteFrame;
/**
* A local segment queue which takes the raw data out from mRawSegment in the
* call of GetEncodedTrack(). Since we implement the fixed FPS encoding
* policy, it needs to be global in order to store the leftover segments
* taken from mRawSegment.
*/
VideoSegment mSourceSegment;
// VP8 relative members.
// Codec context structure.
nsAutoPtr<vpx_codec_ctx_t> mVPXContext;
// Image Descriptor.
nsAutoPtr<vpx_image_t> mVPXImageWrapper;
};
} // namespace mozilla
#endif

View File

@ -0,0 +1,238 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "VorbisTrackEncoder.h"
#include <ogg/ogg.h>
#include <vorbis/vorbisenc.h>
#include "WebMWriter.h"
// One actually used: Encoding using a VBR quality mode. The usable range is -.1
// (lowest quality, smallest file) to 1. (highest quality, largest file).
// Example quality mode .4: 44kHz stereo coupled, roughly 128kbps VBR
// ret = vorbis_encode_init_vbr(&vi,2,44100,.4);
static const float BASE_QUALITY = 0.4f;
namespace mozilla {
#undef LOG
#ifdef PR_LOGGING
PRLogModuleInfo* gVorbisTrackEncoderLog;
#define VORBISLOG(msg, ...) PR_LOG(gVorbisTrackEncoderLog, PR_LOG_DEBUG, \
(msg, ##__VA_ARGS__))
#else
#define VORBISLOG(msg, ...)
#endif
VorbisTrackEncoder::VorbisTrackEncoder()
: AudioTrackEncoder()
{
MOZ_COUNT_CTOR(VorbisTrackEncoder);
#ifdef PR_LOGGING
if (!gVorbisTrackEncoderLog) {
gVorbisTrackEncoderLog = PR_NewLogModule("VorbisTrackEncoder");
}
#endif
}
VorbisTrackEncoder::~VorbisTrackEncoder()
{
MOZ_COUNT_DTOR(VorbisTrackEncoder);
if (mInitialized) {
vorbis_block_clear(&mVorbisBlock);
vorbis_dsp_clear(&mVorbisDsp);
vorbis_info_clear(&mVorbisInfo);
}
}
nsresult
VorbisTrackEncoder::Init(int aChannels, int aSamplingRate)
{
if (aChannels <= 0 || aChannels > 8) {
VORBISLOG("aChannels <= 0 || aChannels > 8");
return NS_ERROR_INVALID_ARG;
}
// This monitor is used to wake up other methods that are waiting for encoder
// to be completely initialized.
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
mChannels = aChannels;
mSamplingRate = aSamplingRate;
int ret = 0;
vorbis_info_init(&mVorbisInfo);
ret = vorbis_encode_init_vbr(&mVorbisInfo, mChannels, mSamplingRate,
BASE_QUALITY);
mInitialized = (ret == 0);
if (mInitialized) {
// Set up the analysis state and auxiliary encoding storage
vorbis_analysis_init(&mVorbisDsp, &mVorbisInfo);
vorbis_block_init(&mVorbisDsp, &mVorbisBlock);
}
mon.NotifyAll();
return ret == 0 ? NS_OK : NS_ERROR_FAILURE;
}
void VorbisTrackEncoder::WriteLacing(nsTArray<uint8_t> *aOutput, int32_t aLacing)
{
while (aLacing > 255) {
aLacing -= 255;
aOutput->AppendElement(255);
}
aOutput->AppendElement((uint8_t)aLacing);
}
already_AddRefed<TrackMetadataBase>
VorbisTrackEncoder::GetMetadata()
{
{
// Wait if encoder is not initialized.
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
while (!mCanceled && !mInitialized) {
mon.Wait();
}
}
if (mCanceled || mEncodingComplete) {
return nullptr;
}
// Vorbis codec specific data
// http://matroska.org/technical/specs/codecid/index.html
nsRefPtr<VorbisMetadata> meta = new VorbisMetadata();
meta->mBitDepth = 32; // float for desktop
meta->mChannels = mChannels;
meta->mSamplingFrequency = mSamplingRate;
ogg_packet header;
ogg_packet header_comm;
ogg_packet header_code;
// Add comment
vorbis_comment vorbisComment;
vorbis_comment_init(&vorbisComment);
vorbis_comment_add_tag(&vorbisComment, "ENCODER",
NS_LITERAL_CSTRING("Mozilla VorbisTrackEncoder " MOZ_APP_UA_VERSION).get());
vorbis_analysis_headerout(&mVorbisDsp, &vorbisComment,
&header,&header_comm, &header_code);
vorbis_comment_clear(&vorbisComment);
// number of distinct packets - 1
meta->mData.AppendElement(2);
// Xiph-style lacing header.bytes, header_comm.bytes
WriteLacing(&(meta->mData), header.bytes);
WriteLacing(&(meta->mData), header_comm.bytes);
// Append the three packets
meta->mData.AppendElements(header.packet, header.bytes);
meta->mData.AppendElements(header_comm.packet, header_comm.bytes);
meta->mData.AppendElements(header_code.packet, header_code.bytes);
return meta.forget();
}
void
VorbisTrackEncoder::GetEncodedFrames(EncodedFrameContainer& aData)
{
// vorbis does some data preanalysis, then divvies up blocks for
// more involved (potentially parallel) processing. Get a single
// block for encoding now.
while (vorbis_analysis_blockout(&mVorbisDsp, &mVorbisBlock) == 1) {
ogg_packet oggPacket;
if (vorbis_analysis(&mVorbisBlock, &oggPacket) == 0) {
VORBISLOG("vorbis_analysis_blockout block size %d", oggPacket.bytes);
EncodedFrame* audiodata = new EncodedFrame();
audiodata->SetFrameType(EncodedFrame::AUDIO_FRAME);
nsTArray<uint8_t> frameData;
frameData.AppendElements(oggPacket.packet, oggPacket.bytes);
audiodata->SetFrameData(&frameData);
aData.AppendEncodedFrame(audiodata);
}
}
}
nsresult
VorbisTrackEncoder::GetEncodedTrack(EncodedFrameContainer& aData)
{
if (mEosSetInEncoder) {
return NS_OK;
}
nsAutoPtr<AudioSegment> sourceSegment;
sourceSegment = new AudioSegment();
{
// Move all the samples from mRawSegment to sourceSegment. We only hold
// the monitor in this block.
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
// Wait if mEncoder is not initialized, or when not enough raw data, but is
// not the end of stream nor is being canceled.
while (!mCanceled && mRawSegment.GetDuration() < GetPacketDuration() &&
!mEndOfStream) {
mon.Wait();
}
VORBISLOG("GetEncodedTrack passes wait, duration is %lld\n",
mRawSegment.GetDuration());
if (mCanceled || mEncodingComplete) {
return NS_ERROR_FAILURE;
}
sourceSegment->AppendFrom(&mRawSegment);
}
if (mEndOfStream && (sourceSegment->GetDuration() == 0)
&& !mEosSetInEncoder) {
mEncodingComplete = true;
mEosSetInEncoder = true;
VORBISLOG("[Vorbis] Done encoding.");
vorbis_analysis_wrote(&mVorbisDsp, 0);
GetEncodedFrames(aData);
return NS_OK;
}
// Start encoding data.
AudioSegment::ChunkIterator iter(*sourceSegment);
AudioDataValue **vorbisBuffer =
vorbis_analysis_buffer(&mVorbisDsp, (int)sourceSegment->GetDuration());
int framesCopied = 0;
nsAutoTArray<AudioDataValue, 9600> interleavedPcm;
nsAutoTArray<AudioDataValue, 9600> nonInterleavedPcm;
interleavedPcm.SetLength(sourceSegment->GetDuration() * mChannels);
nonInterleavedPcm.SetLength(sourceSegment->GetDuration() * mChannels);
while (!iter.IsEnded()) {
AudioChunk chunk = *iter;
int frameToCopy = chunk.GetDuration();
if (!chunk.IsNull()) {
InterleaveTrackData(chunk, frameToCopy, mChannels,
interleavedPcm.Elements() + framesCopied * mChannels);
} else { // empty data
memset(interleavedPcm.Elements() + framesCopied * mChannels, 0,
frameToCopy * mChannels * sizeof(AudioDataValue));
}
framesCopied += frameToCopy;
iter.Next();
}
// De-interleave the interleavedPcm.
DeInterleaveTrackData(interleavedPcm.Elements(), framesCopied, mChannels,
nonInterleavedPcm.Elements());
// Copy the nonInterleavedPcm to vorbis buffer.
for(uint8_t i = 0; i < mChannels; ++i) {
memcpy(vorbisBuffer[i], nonInterleavedPcm.Elements() + framesCopied * i,
framesCopied * sizeof(AudioDataValue));
}
// Now the vorbisBuffer contain the all data in non-interleaved.
// Tell the library how much we actually submitted.
vorbis_analysis_wrote(&mVorbisDsp, framesCopied);
VORBISLOG("vorbis_analysis_wrote framesCopied %d\n", framesCopied);
GetEncodedFrames(aData);
return NS_OK;
}
} // namespace mozilla

View File

@ -0,0 +1,54 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef VorbisTrackEncoder_h_
#define VorbisTrackEncoder_h_
#include "TrackEncoder.h"
#include "nsCOMPtr.h"
#include <vorbis/codec.h>
namespace mozilla {
class VorbisTrackEncoder : public AudioTrackEncoder
{
public:
VorbisTrackEncoder();
virtual ~VorbisTrackEncoder();
already_AddRefed<TrackMetadataBase> GetMetadata() MOZ_FINAL MOZ_OVERRIDE;
nsresult GetEncodedTrack(EncodedFrameContainer& aData) MOZ_FINAL MOZ_OVERRIDE;
protected:
/**
* http://xiph.org/vorbis/doc/libvorbis/vorbis_analysis_buffer.html
* We use 1024 samples for the write buffer; libvorbis will construct packets
* with the appropriate duration for the encoding mode internally.
*/
int GetPacketDuration() MOZ_FINAL MOZ_OVERRIDE {
return 1024;
}
nsresult Init(int aChannels, int aSamplingRate) MOZ_FINAL MOZ_OVERRIDE;
private:
// Write Xiph-style lacing to aOutput.
void WriteLacing(nsTArray<uint8_t> *aOutput, int32_t aLacing);
// Get the encoded data from vorbis encoder and append into aData.
void GetEncodedFrames(EncodedFrameContainer& aData);
// vorbis codec members
// Struct that stores all the static vorbis bitstream settings.
vorbis_info mVorbisInfo;
// Central working state for the PCM->packet encoder.
vorbis_dsp_state mVorbisDsp;
// Local working space for PCM->packet encode.
vorbis_block mVorbisBlock;
};
}
#endif

View File

@ -20,13 +20,21 @@ UNIFIED_SOURCES += [
'TrackEncoder.cpp',
]
if CONFIG['MOZ_OMX_ENCODER']:
EXPORTS += ['OmxTrackEncoder.h']
UNIFIED_SOURCES += ['OmxTrackEncoder.cpp']
if CONFIG['MOZ_OPUS']:
EXPORTS += ['OpusTrackEncoder.h']
UNIFIED_SOURCES += ['OpusTrackEncoder.cpp']
if CONFIG['MOZ_OMX_ENCODER']:
EXPORTS += ['OmxTrackEncoder.h']
UNIFIED_SOURCES += ['OmxTrackEncoder.cpp']
if CONFIG['MOZ_WEBM_ENCODER']:
EXPORTS += ['VorbisTrackEncoder.h',
'VP8TrackEncoder.h',
]
UNIFIED_SOURCES += ['VorbisTrackEncoder.cpp',
'VP8TrackEncoder.cpp',
]
FAIL_ON_WARNINGS = True

View File

@ -256,6 +256,7 @@ support-files =
[test_mediarecorder_reload_crash.html]
[test_mediarecorder_record_immediate_stop.html]
[test_mediarecorder_record_session.html]
[test_mediarecorder_unsupported_src.html]
[test_playback.html]
[test_seekLies.html]
[test_media_sniffer.html]

View File

@ -0,0 +1,90 @@
<html>
<head>
<title>Bug 957439 - Media Recording - Assertion fail at Pause if unsupported input stream.</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript" src="manifest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=957439">Mozilla Bug 957439</a>
<pre id="test">
<script class="testbody" type="text/javascript">
function startTest() {
navigator.mozGetUserMedia({audio: false, video: true, fake: true},
function(stream) {
// Expected callback sequence should be:
// 1. onerror (from start)
// 2. onerror (from pause)
// 3. ondataavailable
// 4. onstop
var callbackStep = 0;
var mediaRecorder = new MediaRecorder(stream);
is(mediaRecorder.stream, stream, 'Stream should be provided on creation');
mediaRecorder.onerror = function (e) {
callbackStep++;
ok(callbackStep < 3, 'onerror callback fired as expected.');
is(e.name, 'GenericError', 'Error name should be GenericError.');
is(mediaRecorder.mimeType, '', 'mimetype should be empty');
is(mediaRecorder.state, 'recording', 'state is recording');
info('onerror callback fired');
}
mediaRecorder.onwarning = function () {
ok(false, 'Unexpected onwarning callback fired.');
};
mediaRecorder.ondataavailable = function (evt) {
callbackStep++;
info('ondataavailable callback fired');
is(callbackStep, 3, 'should fired ondataavailable callback');
is(evt.data.size, 0, 'data size should be zero');
ok(evt instanceof BlobEvent,
'Events fired from ondataavailable should be BlobEvent');
is(evt.data.type, '', 'encoder start fail, blob miemType should be empty');
};
mediaRecorder.onstop = function() {
callbackStep++;
info('onstop callback fired');
is(mediaRecorder.state, 'inactive', 'state should be inactive');
is(callbackStep, 4, 'should fired onstop callback');
SimpleTest.finish();
};
try {
mediaRecorder.start();
} catch(e) {
ok(false, 'Should not get exception in start call.');
}
try {
mediaRecorder.pause();
} catch(e) {
ok(false, 'Should not get exception in pause call.');
}
},
function(err) {
ok(false, 'Unexpected error fired with: ' + err);
SimpleTest.finish();
}
);
}
SimpleTest.waitForExplicitFinish();
// In order to generate an "unsupported stream", pref off video encoding to
// make the platform support audio encoding only.
SpecialPowers.pushPrefEnv(
{
"set": [
["media.encoder.webm.enabled", false]
]
}, startTest);
</script>
</head>
</html>

View File

@ -0,0 +1,177 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "EbmlComposer.h"
#include "libmkv/EbmlIDs.h"
#include "libmkv/EbmlWriter.h"
#include "libmkv/WebMElement.h"
#include "prtime.h"
namespace mozilla {
// Timecode scale in nanoseconds
static const unsigned long TIME_CODE_SCALE = 1000000;
// The WebM header size without audio CodecPrivateData
static const int32_t DEFAULT_HEADER_SIZE = 1024;
void EbmlComposer::GenerateHeader()
{
// Write the EBML header.
EbmlGlobal ebml;
// The WEbM header default size usually smaller than 1k.
nsAutoArrayPtr<uint8_t> buffer(new uint8_t[DEFAULT_HEADER_SIZE +
mCodecPrivateData.Length()]);
ebml.buf = buffer.get();
ebml.offset = 0;
writeHeader(&ebml);
{
EbmlLoc segEbmlLoc, ebmlLocseg, ebmlLoc;
Ebml_StartSubElement(&ebml, &segEbmlLoc, Segment);
{
Ebml_StartSubElement(&ebml, &ebmlLocseg, SeekHead);
// Todo: We don't know the exact sizes of encoded data and ignore this section.
Ebml_EndSubElement(&ebml, &ebmlLocseg);
writeSegmentInformation(&ebml, &ebmlLoc, TIME_CODE_SCALE, 0);
{
EbmlLoc trackLoc;
Ebml_StartSubElement(&ebml, &trackLoc, Tracks);
{
char cid_string[8];
// Video
if (mWidth > 0 && mHeight > 0) {
strcpy(cid_string, "V_VP8");
writeVideoTrack(&ebml, 0x1, 0, cid_string,
mWidth, mHeight, mFrameRate);
}
// Audio
if (mCodecPrivateData.Length() > 0) {
strcpy(cid_string, "A_VORBIS");
writeAudioTrack(&ebml, 0x2, 0x0, cid_string, mSampleFreq,
mChannels, mCodecPrivateData.Elements(),
mCodecPrivateData.Length());
}
}
Ebml_EndSubElement(&ebml, &trackLoc);
}
}
// The Recording length is unknow and ignore write the whole Segment element size
}
MOZ_ASSERT_IF(ebml.offset > DEFAULT_HEADER_SIZE + mCodecPrivateData.Length(),
"write more data > EBML_BUFFER_SIZE");
mClusterBuffs.AppendElement();
mClusterBuffs.LastElement().SetLength(ebml.offset);
memcpy(mClusterBuffs.LastElement().Elements(), ebml.buf, ebml.offset);
}
void EbmlComposer::FinishCluster()
{
MOZ_ASSERT(mClusterLengthLoc > 0 );
MOZ_ASSERT(mClusterHeaderIndex > 0);
for (uint32_t i = 0; i < mClusterBuffs.Length(); i ++ ) {
mClusterCanFlushBuffs.AppendElement()->SwapElements(mClusterBuffs[i]);
}
mClusterBuffs.Clear();
EbmlGlobal ebml;
EbmlLoc ebmlLoc;
ebmlLoc.offset = mClusterLengthLoc;
ebml.offset = mClusterCanFlushBuffs[mClusterHeaderIndex].Length();
ebml.buf = mClusterCanFlushBuffs[mClusterHeaderIndex].Elements();
Ebml_EndSubElement(&ebml, &ebmlLoc);
mClusterHeaderIndex = 0;
mClusterLengthLoc = 0;
}
void
EbmlComposer::WriteSimpleBlock(EncodedFrame* aFrame)
{
EbmlGlobal ebml;
ebml.offset = 0;
if (aFrame->GetFrameType() == EncodedFrame::FrameType::I_FRAME && mClusterHeaderIndex > 0) {
FinishCluster();
}
mClusterBuffs.AppendElement();
mClusterBuffs.LastElement().SetLength(aFrame->GetFrameData().Length() + DEFAULT_HEADER_SIZE);
ebml.buf = mClusterBuffs.LastElement().Elements();
if (aFrame->GetFrameType() == EncodedFrame::FrameType::I_FRAME) {
EbmlLoc ebmlLoc;
Ebml_StartSubElement(&ebml, &ebmlLoc, Cluster);
mClusterHeaderIndex = mClusterBuffs.Length() - 1; // current cluster header array index
mClusterLengthLoc = ebmlLoc.offset;
if (aFrame->GetFrameType() != EncodedFrame::FrameType::AUDIO_FRAME) {
mClusterTimecode = aFrame->GetTimeStamp() / PR_USEC_PER_MSEC;
}
Ebml_SerializeUnsigned(&ebml, Timecode, mClusterTimecode);
}
if (aFrame->GetFrameType() != EncodedFrame::FrameType::AUDIO_FRAME) {
short timeCode = aFrame->GetTimeStamp() / PR_USEC_PER_MSEC - mClusterTimecode;
writeSimpleBlock(&ebml, 0x1, timeCode, aFrame->GetFrameType() ==
EncodedFrame::FrameType::I_FRAME,
0, 0, (unsigned char*)aFrame->GetFrameData().Elements(),
aFrame->GetFrameData().Length());
} else {
writeSimpleBlock(&ebml, 0x2, 0, false,
0, 0, (unsigned char*)aFrame->GetFrameData().Elements(),
aFrame->GetFrameData().Length());
}
MOZ_ASSERT_IF(ebml.offset > DEFAULT_HEADER_SIZE + aFrame->GetFrameData().Length(),
"write more data > EBML_BUFFER_SIZE");
mClusterBuffs.LastElement().SetLength(ebml.offset);
}
void
EbmlComposer::SetVideoConfig(uint32_t aWidth, uint32_t aHeight,
float aFrameRate)
{
MOZ_ASSERT(aWidth > 0, "Width should > 0");
MOZ_ASSERT(aHeight > 0, "Height should > 0");
MOZ_ASSERT(aFrameRate > 0, "FrameRate should > 0");
mWidth = aWidth;
mHeight = aHeight;
mFrameRate = aFrameRate;
}
void
EbmlComposer::SetAudioConfig(uint32_t aSampleFreq, uint32_t aChannels,
uint32_t aBitDepth)
{
MOZ_ASSERT(aSampleFreq > 0, "SampleFreq should > 0");
MOZ_ASSERT(aBitDepth > 0, "BitDepth should > 0");
MOZ_ASSERT(aChannels > 0, "Channels should > 0");
mSampleFreq = aSampleFreq;
mBitDepth = aBitDepth;
mChannels = aChannels;
}
void
EbmlComposer::ExtractBuffer(nsTArray<nsTArray<uint8_t> >* aDestBufs,
uint32_t aFlag)
{
if ((aFlag & ContainerWriter::FLUSH_NEEDED) && mClusterHeaderIndex > 0) {
FinishCluster();
}
// aDestBufs may have some element
for (uint32_t i = 0; i < mClusterCanFlushBuffs.Length(); i ++ ) {
aDestBufs->AppendElement()->SwapElements(mClusterCanFlushBuffs[i]);
}
mClusterCanFlushBuffs.Clear();
}
EbmlComposer::EbmlComposer()
: mClusterHeaderIndex(0)
, mClusterLengthLoc(0)
, mClusterTimecode(0)
, mWidth(0)
, mHeight(0)
, mFrameRate(0)
, mSampleFreq(0)
, mBitDepth(0)
, mChannels(0)
{}
}

View File

@ -0,0 +1,75 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef EbmlComposer_h_
#define EbmlComposer_h_
#include "nsTArray.h"
#include "ContainerWriter.h"
namespace mozilla {
/*
* A WebM muxer helper for package the valid WebM format.
*/
class EbmlComposer {
public:
EbmlComposer();
/*
* Assign the parameter which header required.
*/
void SetVideoConfig(uint32_t aWidth, uint32_t aHeight, float aFrameRate);
void SetAudioConfig(uint32_t aSampleFreq, uint32_t aChannels,
uint32_t bitDepth);
/*
* Set the CodecPrivateData for writing in header.
*/
void SetAudioCodecPrivateData(nsTArray<uint8_t>& aBufs)
{
mCodecPrivateData.AppendElements(aBufs);
}
/*
* Generate the whole WebM header and output to mBuff.
*/
void GenerateHeader();
/*
* Insert media encoded buffer into muxer and it would be package
* into SimpleBlock. If no cluster is opened, new cluster will start for writing.
*/
void WriteSimpleBlock(EncodedFrame* aFrame);
/*
* Get valid cluster data.
*/
void ExtractBuffer(nsTArray<nsTArray<uint8_t> >* aDestBufs,
uint32_t aFlag = 0);
private:
// Close current cluster and move data to mClusterCanFlushBuffs.
void FinishCluster();
// The temporary storage for cluster data.
nsTArray<nsTArray<uint8_t> > mClusterBuffs;
// The storage which contain valid cluster data.
nsTArray<nsTArray<uint8_t> > mClusterCanFlushBuffs;
// Indicate the header index in mClusterBuffs.
uint32_t mClusterHeaderIndex;
// The cluster length position.
uint64_t mClusterLengthLoc;
// Audio codec specific header data.
nsTArray<uint8_t> mCodecPrivateData;
// The timecode of the cluster.
uint64_t mClusterTimecode;
// Video configuration
int mWidth;
int mHeight;
float mFrameRate;
// Audio configuration
float mSampleFreq;
int mBitDepth;
int mChannels;
};
}
#endif

View File

@ -0,0 +1,64 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WebMWriter.h"
#include "EbmlComposer.h"
namespace mozilla {
WebMWriter::WebMWriter(uint32_t aTrackTypes) : ContainerWriter()
{
mMetadataRequiredFlag = aTrackTypes;
mEbmlComposer = new EbmlComposer();
}
nsresult
WebMWriter::WriteEncodedTrack(const EncodedFrameContainer& aData,
uint32_t aFlags)
{
for (uint32_t i = 0 ; i < aData.GetEncodedFrames().Length(); i++) {
mEbmlComposer->WriteSimpleBlock(aData.GetEncodedFrames().ElementAt(i).get());
}
return NS_OK;
}
nsresult
WebMWriter::GetContainerData(nsTArray<nsTArray<uint8_t> >* aOutputBufs,
uint32_t aFlags)
{
mEbmlComposer->ExtractBuffer(aOutputBufs, aFlags);
if (aFlags & ContainerWriter::FLUSH_NEEDED) {
mIsWritingComplete = true;
}
return NS_OK;
}
nsresult
WebMWriter::SetMetadata(TrackMetadataBase* aMetadata)
{
MOZ_ASSERT(aMetadata);
if (aMetadata->GetKind() == TrackMetadataBase::METADATA_VP8) {
VP8Metadata* meta = static_cast<VP8Metadata*>(aMetadata);
MOZ_ASSERT(meta, "Cannot find vp8 encoder metadata");
mEbmlComposer->SetVideoConfig(meta->mWidth, meta->mHeight,
meta->mEncodedFrameRate);
mMetadataRequiredFlag = mMetadataRequiredFlag & ~ContainerWriter::HAS_VIDEO;
}
if (aMetadata->GetKind() == TrackMetadataBase::METADATA_VORBIS) {
VorbisMetadata* meta = static_cast<VorbisMetadata*>(aMetadata);
MOZ_ASSERT(meta, "Cannot find vorbis encoder metadata");
mEbmlComposer->SetAudioConfig(meta->mSamplingFrequency, meta->mChannels, meta->mBitDepth);
mEbmlComposer->SetAudioCodecPrivateData(meta->mData);
mMetadataRequiredFlag = mMetadataRequiredFlag & ~ContainerWriter::HAS_AUDIO;
}
if (!mMetadataRequiredFlag) {
mEbmlComposer->GenerateHeader();
}
return NS_OK;
}
} // mozilla namespace

View File

@ -0,0 +1,70 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef WebMWriter_h_
#define WebMWriter_h_
#include "ContainerWriter.h"
namespace mozilla {
class EbmlComposer;
// Vorbis meta data structure
class VorbisMetadata : public TrackMetadataBase
{
public:
nsTArray<uint8_t> mData;
int32_t mChannels;
int32_t mBitDepth;
float mSamplingFrequency;
MetadataKind GetKind() const MOZ_OVERRIDE { return METADATA_VORBIS; }
};
// VP8 meta data structure
class VP8Metadata : public TrackMetadataBase
{
public:
int32_t mWidth;
int32_t mHeight;
int32_t mEncodedFrameRate;
MetadataKind GetKind() const MOZ_OVERRIDE { return METADATA_VP8; }
};
/**
* WebM writer helper
* This class accepts encoder to set audio or video meta data or
* encoded data to ebml Composer, and get muxing data through GetContainerData.
* The ctor/dtor run in the MediaRecorder thread, others run in MediaEncoder thread.
*/
class WebMWriter : public ContainerWriter
{
public:
// aTrackTypes indicate this muxer should multiplex into Video only or A/V foramt.
// Run in MediaRecorder thread
WebMWriter(uint32_t aTrackTypes);
// WriteEncodedTrack inserts raw packets into WebM stream.
nsresult WriteEncodedTrack(const EncodedFrameContainer &aData,
uint32_t aFlags = 0) MOZ_OVERRIDE;
// GetContainerData outputs multiplexing data.
// aFlags indicates the muxer should enter into finished stage and flush out
// queue data.
nsresult GetContainerData(nsTArray<nsTArray<uint8_t> >* aOutputBufs,
uint32_t aFlags = 0) MOZ_OVERRIDE;
// Assign metadata into muxer
nsresult SetMetadata(TrackMetadataBase* aMetadata) MOZ_OVERRIDE;
private:
nsAutoPtr<EbmlComposer> mEbmlComposer;
// Indicate what kind of meta data needed in the writer.
// If this value become 0, it means writer can start to generate header.
uint8_t mMetadataRequiredFlag;
};
}
#endif

View File

@ -15,6 +15,12 @@ UNIFIED_SOURCES += [
'WebMReader.cpp',
]
if CONFIG['MOZ_WEBM_ENCODER']:
EXPORTS += ['WebMWriter.h']
UNIFIED_SOURCES += ['EbmlComposer.cpp',
'WebMWriter.cpp',
]
FAIL_ON_WARNINGS = True
FINAL_LIBRARY = 'gklayout'

View File

@ -0,0 +1,42 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef B2G_BDROID_BUILDCFG_H
#define B2G_BDROID_BUILDCFG_H
/**
* This header defines B2G common bluedroid build configuration.
*
* This header is included by
* $(BOARD_BLUETOOTH_BDROID_BUILDCFG_INCLUDE_DIR)/bdroid_buildcfg.h,
* which applies external configuration onto bluedroid.
*/
/******************************************************************************
**
** HSP, HFP
**
******************************************************************************/
/* AG feature masks */
#define BTIF_HF_FEATURES ( BTA_AG_FEAT_3WAY | \
BTA_AG_FEAT_REJECT | \
BTA_AG_FEAT_ECS | \
BTA_AG_FEAT_EXTERR)
/* CHLD values */
#define BTA_AG_CHLD_VAL "(0,1,2)"
#endif /* B2G_BDROID_BUILDCFG_H */

View File

@ -3657,8 +3657,8 @@ let RIL = {
_sendCallError: function(callIndex, errorMsg) {
this.sendChromeMessage({rilMessageType: "callError",
callIndex: callIndex,
errorMsg: errorMsg});
callIndex: callIndex,
errorMsg: errorMsg});
},
_sendDataCallError: function(message, errorCode) {
@ -5095,8 +5095,7 @@ RIL[REQUEST_DIAL] = function REQUEST_DIAL(length, options) {
if (options.rilRequestError) {
// The connection is not established yet.
options.callIndex = -1;
this._sendCallError(options.callIndex,
RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError]);
this.getFailCauseCode(options);
}
};
RIL[REQUEST_GET_IMSI] = function REQUEST_GET_IMSI(length, options) {
@ -9666,6 +9665,13 @@ let ICCPDUHelper = {
writeNumberWithLength: function(number) {
if (number) {
let numStart = number[0] == "+" ? 1 : 0;
number = number.substring(0, numStart) +
number.substring(numStart)
.replace(/[^0-9*#,]/g, "")
.replace(/\*/g, "a")
.replace(/\#/g, "b")
.replace(/\,/g, "c");
let numDigits = number.length - numStart;
if (numDigits > ADN_MAX_NUMBER_DIGITS) {
number = number.substring(0, ADN_MAX_NUMBER_DIGITS + numStart);

View File

@ -496,27 +496,35 @@ add_test(function test_write_number_with_length() {
let helper = worker.GsmPDUHelper;
let iccHelper = worker.ICCPDUHelper;
// without +
let number_1 = "123456789";
iccHelper.writeNumberWithLength(number_1);
let numLen = helper.readHexOctet();
do_check_eq(number_1, iccHelper.readDiallingNumber(numLen));
for (let i = 0; i < (ADN_MAX_BCD_NUMBER_BYTES - numLen); i++) {
do_check_eq(0xff, helper.readHexOctet());
function test(number, expectedNumber) {
expectedNumber = expectedNumber || number;
iccHelper.writeNumberWithLength(number);
let numLen = helper.readHexOctet();
do_check_eq(expectedNumber, iccHelper.readDiallingNumber(numLen));
for (let i = 0; i < (ADN_MAX_BCD_NUMBER_BYTES - numLen); i++) {
do_check_eq(0xff, helper.readHexOctet());
}
}
// without +
test("123456789");
// with +
let number_2 = "+987654321";
iccHelper.writeNumberWithLength(number_2);
numLen = helper.readHexOctet();
do_check_eq(number_2, iccHelper.readDiallingNumber(numLen));
for (let i = 0; i < (ADN_MAX_BCD_NUMBER_BYTES - numLen); i++) {
do_check_eq(0xff, helper.readHexOctet());
}
test("+987654321");
// extended BCD coding
test("1*2#3,4*5#6,");
// with + and extended BCD coding
test("+1*2#3,4*5#6,");
// non-supported characters should not be written.
test("(1)23-456+789", "123456789");
test("++(01)2*3-4#5,6+7(8)9*0#1,", "+012*34#5,6789*0#1,");
// null
let number_3;
iccHelper.writeNumberWithLength(number_3);
iccHelper.writeNumberWithLength(null);
for (let i = 0; i < (ADN_MAX_BCD_NUMBER_BYTES + 1); i++) {
do_check_eq(0xff, helper.readHexOctet());
}

View File

@ -29,6 +29,17 @@ nestegg_tstamp_scale
nestegg_has_cues
nestegg_sniff
#endif
#ifdef MOZ_WEBM_ENCODER
writeSimpleBlock
writeHeader
writeSegmentInformation
writeVideoTrack
writeAudioTrack
Ebml_Serialize
Ebml_SerializeUnsigned
Ebml_StartSubElement
Ebml_EndSubElement
#endif
#ifdef MOZ_VPX
#ifndef MOZ_NATIVE_LIBVPX
vpx_codec_control_

100
media/libmkv/AUTHORS Normal file
View File

@ -0,0 +1,100 @@
# This file is automatically generated from the git commit history
# by tools/gen_authors.sh.
Aaron Watry <awatry@gmail.com>
Abo Talib Mahfoodh <ab.mahfoodh@gmail.com>
Adrian Grange <agrange@google.com>
Ahmad Sharif <asharif@google.com>
Alexander Voronov <avoronov@graphics.cs.msu.ru>
Alex Converse <alex.converse@gmail.com>
Alexis Ballier <aballier@gentoo.org>
Alok Ahuja <waveletcoeff@gmail.com>
Alpha Lam <hclam@google.com>
A.Mahfoodh <ab.mahfoodh@gmail.com>
Ami Fischman <fischman@chromium.org>
Andoni Morales Alastruey <ylatuya@gmail.com>
Andres Mejia <mcitadel@gmail.com>
Aron Rosenberg <arosenberg@logitech.com>
Attila Nagy <attilanagy@google.com>
changjun.yang <changjun.yang@intel.com>
chm <chm@rock-chips.com>
Christian Duvivier <cduvivier@google.com>
Daniel Kang <ddkang@google.com>
Deb Mukherjee <debargha@google.com>
Dmitry Kovalev <dkovalev@google.com>
Dragan Mrdjan <dmrdjan@mips.com>
Erik Niemeyer <erik.a.niemeyer@gmail.com>
Fabio Pedretti <fabio.ped@libero.it>
Frank Galligan <fgalligan@google.com>
Fredrik Söderquist <fs@opera.com>
Fritz Koenig <frkoenig@google.com>
Gaute Strokkenes <gaute.strokkenes@broadcom.com>
Giuseppe Scrivano <gscrivano@gnu.org>
Guillaume Martres <gmartres@google.com>
Guillermo Ballester Valor <gbvalor@gmail.com>
Hangyu Kuang <hkuang@google.com>
Henrik Lundin <hlundin@google.com>
Hui Su <huisu@google.com>
Ivan Maltz <ivanmaltz@google.com>
James Berry <jamesberry@google.com>
James Zern <jzern@google.com>
Jan Kratochvil <jan.kratochvil@redhat.com>
Janne Salonen <jsalonen@google.com>
Jeff Faust <jfaust@google.com>
Jeff Muizelaar <jmuizelaar@mozilla.com>
Jeff Petkau <jpet@chromium.org>
Jim Bankoski <jimbankoski@google.com>
Jingning Han <jingning@google.com>
Johann Koenig <johannkoenig@google.com>
John Koleszar <jkoleszar@google.com>
Joshua Bleecher Snyder <josh@treelinelabs.com>
Joshua Litt <joshualitt@google.com>
Justin Clift <justin@salasaga.org>
Justin Lebar <justin.lebar@gmail.com>
KO Myung-Hun <komh@chollian.net>
Lou Quillio <louquillio@google.com>
Luca Barbato <lu_zero@gentoo.org>
Makoto Kato <makoto.kt@gmail.com>
Mans Rullgard <mans@mansr.com>
Marco Paniconi <marpan@google.com>
Mark Mentovai <mark@chromium.org>
Martin Ettl <ettl.martin78@googlemail.com>
Martin Storsjo <martin@martin.st>
Matthew Heaney <matthewjheaney@chromium.org>
Michael Kohler <michaelkohler@live.com>
Mike Frysinger <vapier@chromium.org>
Mike Hommey <mhommey@mozilla.com>
Mikhal Shemer <mikhal@google.com>
Morton Jonuschat <yabawock@gmail.com>
Parag Salasakar <img.mips1@gmail.com>
Pascal Massimino <pascal.massimino@gmail.com>
Patrik Westin <patrik.westin@gmail.com>
Paul Wilkins <paulwilkins@google.com>
Pavol Rusnak <stick@gk2.sk>
Paweł Hajdan <phajdan@google.com>
Philip Jägenstedt <philipj@opera.com>
Priit Laes <plaes@plaes.org>
Rafael Ávila de Espíndola <rafael.espindola@gmail.com>
Rafaël Carré <funman@videolan.org>
Ralph Giles <giles@xiph.org>
Rob Bradford <rob@linux.intel.com>
Ronald S. Bultje <rbultje@google.com>
Sami Pietilä <samipietila@google.com>
Scott Graham <scottmg@chromium.org>
Scott LaVarnway <slavarnway@google.com>
Shimon Doodkin <helpmepro1@gmail.com>
Stefan Holmer <holmer@google.com>
Suman Sunkara <sunkaras@google.com>
Taekhyun Kim <takim@nvidia.com>
Takanori MATSUURA <t.matsuu@gmail.com>
Tamar Levy <tamar.levy@intel.com>
Tero Rintaluoma <teror@google.com>
Thijs Vermeir <thijsvermeir@gmail.com>
Timothy B. Terriberry <tterribe@xiph.org>
Tom Finegan <tomfinegan@google.com>
Vignesh Venkatasubramanian <vigneshv@google.com>
Yaowu Xu <yaowu@google.com>
Yunqing Wang <yunqingwang@google.com>
Google Inc.
The Mozilla Foundation
The Xiph.Org Foundation

View File

@ -0,0 +1,79 @@
// #include <strmif.h>
#include "EbmlBufferWriter.h"
#include "EbmlWriter.h"
// #include <cassert>
// #include <limits>
// #include <malloc.h> //_alloca
#include <stdlib.h>
#include <wchar.h>
#include <string.h>
void
Ebml_Serialize(EbmlGlobal *glob, const void *buffer_in, int buffer_size, unsigned long len)
{
/* buffer_size:
* 1 - int8_t;
* 2 - int16_t;
* 3 - int32_t;
* 4 - int64_t;
*/
long i;
for(i = len-1; i >= 0; i--) {
unsigned char x;
if (buffer_size == 1) {
x = (char)(*(const int8_t *)buffer_in >> (i * 8));
} else if (buffer_size == 2) {
x = (char)(*(const int16_t *)buffer_in >> (i * 8));
} else if (buffer_size == 4) {
x = (char)(*(const int32_t *)buffer_in >> (i * 8));
} else if (buffer_size == 8) {
x = (char)(*(const int64_t *)buffer_in >> (i * 8));
}
Ebml_Write(glob, &x, 1);
}
}
void Ebml_Write(EbmlGlobal *glob, const void *buffer_in, unsigned long len) {
unsigned char *src = glob->buf;
src += glob->offset;
memcpy(src, buffer_in, len);
glob->offset += len;
}
static void _Serialize(EbmlGlobal *glob, const unsigned char *p, const unsigned char *q) {
while (q != p) {
--q;
memcpy(&(glob->buf[glob->offset]), q, 1);
glob->offset++;
}
}
/*
void Ebml_Serialize(EbmlGlobal *glob, const void *buffer_in, unsigned long len) {
// assert(buf);
const unsigned char *const p = (const unsigned char *)(buffer_in);
const unsigned char *const q = p + len;
_Serialize(glob, p, q);
}
*/
void Ebml_StartSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc, unsigned long class_id) {
unsigned long long unknownLen = 0x01FFFFFFFFFFFFFFLL;
Ebml_WriteID(glob, class_id);
ebmlLoc->offset = glob->offset;
// todo this is always taking 8 bytes, this may need later optimization
Ebml_Serialize(glob, (void *)&unknownLen,sizeof(unknownLen), 8); // this is a key that says lenght unknown
}
void Ebml_EndSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc) {
unsigned long long size = glob->offset - ebmlLoc->offset - 8;
unsigned long long curOffset = glob->offset;
glob->offset = ebmlLoc->offset;
size |= 0x0100000000000000LL;
Ebml_Serialize(glob, &size,sizeof(size), 8);
glob->offset = curOffset;
}

View File

@ -0,0 +1,20 @@
#ifndef EBMLBUFFERWRITER_HPP
#define EBMLBUFFERWRITER_HPP
typedef struct {
unsigned long long offset;
} EbmlLoc;
typedef struct {
unsigned char *buf;
unsigned int length;
unsigned int offset;
} EbmlGlobal;
void Ebml_Write(EbmlGlobal *glob, const void *buffer_in, unsigned long len);
void Ebml_Serialize(EbmlGlobal *glob, const void *buffer_in,
int buffer_size, unsigned long len);
void Ebml_StartSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc, unsigned long class_id);
void Ebml_EndSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc);
#endif

231
media/libmkv/EbmlIDs.h Normal file
View File

@ -0,0 +1,231 @@
/*
* 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.
*/
#ifndef MKV_DEFS_HPP
#define MKV_DEFS_HPP 1
/* Commenting out values not available in webm, but available in matroska */
enum mkv {
EBML = 0x1A45DFA3,
EBMLVersion = 0x4286,
EBMLReadVersion = 0x42F7,
EBMLMaxIDLength = 0x42F2,
EBMLMaxSizeLength = 0x42F3,
DocType = 0x4282,
DocTypeVersion = 0x4287,
DocTypeReadVersion = 0x4285,
/* CRC_32 = 0xBF, */
Void = 0xEC,
SignatureSlot = 0x1B538667,
SignatureAlgo = 0x7E8A,
SignatureHash = 0x7E9A,
SignaturePublicKey = 0x7EA5,
Signature = 0x7EB5,
SignatureElements = 0x7E5B,
SignatureElementList = 0x7E7B,
SignedElement = 0x6532,
/* segment */
Segment = 0x18538067,
/* Meta Seek Information */
SeekHead = 0x114D9B74,
Seek = 0x4DBB,
SeekID = 0x53AB,
SeekPosition = 0x53AC,
/* Segment Information */
Info = 0x1549A966,
/* SegmentUID = 0x73A4, */
/* SegmentFilename = 0x7384, */
/* PrevUID = 0x3CB923, */
/* PrevFilename = 0x3C83AB, */
/* NextUID = 0x3EB923, */
/* NextFilename = 0x3E83BB, */
/* SegmentFamily = 0x4444, */
/* ChapterTranslate = 0x6924, */
/* ChapterTranslateEditionUID = 0x69FC, */
/* ChapterTranslateCodec = 0x69BF, */
/* ChapterTranslateID = 0x69A5, */
TimecodeScale = 0x2AD7B1,
Segment_Duration = 0x4489,
DateUTC = 0x4461,
/* Title = 0x7BA9, */
MuxingApp = 0x4D80,
WritingApp = 0x5741,
/* Cluster */
Cluster = 0x1F43B675,
Timecode = 0xE7,
/* SilentTracks = 0x5854, */
/* SilentTrackNumber = 0x58D7, */
/* Position = 0xA7, */
PrevSize = 0xAB,
BlockGroup = 0xA0,
Block = 0xA1,
/* BlockVirtual = 0xA2, */
BlockAdditions = 0x75A1,
BlockMore = 0xA6,
BlockAddID = 0xEE,
BlockAdditional = 0xA5,
BlockDuration = 0x9B,
/* ReferencePriority = 0xFA, */
ReferenceBlock = 0xFB,
/* ReferenceVirtual = 0xFD, */
/* CodecState = 0xA4, */
/* Slices = 0x8E, */
/* TimeSlice = 0xE8, */
LaceNumber = 0xCC,
/* FrameNumber = 0xCD, */
/* BlockAdditionID = 0xCB, */
/* MkvDelay = 0xCE, */
/* Cluster_Duration = 0xCF, */
SimpleBlock = 0xA3,
/* EncryptedBlock = 0xAF, */
/* Track */
Tracks = 0x1654AE6B,
TrackEntry = 0xAE,
TrackNumber = 0xD7,
TrackUID = 0x73C5,
TrackType = 0x83,
FlagEnabled = 0xB9,
FlagDefault = 0x88,
FlagForced = 0x55AA,
FlagLacing = 0x9C,
/* MinCache = 0x6DE7, */
/* MaxCache = 0x6DF8, */
DefaultDuration = 0x23E383,
/* TrackTimecodeScale = 0x23314F, */
/* TrackOffset = 0x537F, */
MaxBlockAdditionID = 0x55EE,
Name = 0x536E,
Language = 0x22B59C,
CodecID = 0x86,
CodecPrivate = 0x63A2,
CodecName = 0x258688,
/* AttachmentLink = 0x7446, */
/* CodecSettings = 0x3A9697, */
/* CodecInfoURL = 0x3B4040, */
/* CodecDownloadURL = 0x26B240, */
/* CodecDecodeAll = 0xAA, */
/* TrackOverlay = 0x6FAB, */
/* TrackTranslate = 0x6624, */
/* TrackTranslateEditionUID = 0x66FC, */
/* TrackTranslateCodec = 0x66BF, */
/* TrackTranslateTrackID = 0x66A5, */
/* video */
Video = 0xE0,
FlagInterlaced = 0x9A,
WEBM_StereoMode = 0x53B8,
AlphaMode = 0x53C0,
PixelWidth = 0xB0,
PixelHeight = 0xBA,
PixelCropBottom = 0x54AA,
PixelCropTop = 0x54BB,
PixelCropLeft = 0x54CC,
PixelCropRight = 0x54DD,
DisplayWidth = 0x54B0,
DisplayHeight = 0x54BA,
DisplayUnit = 0x54B2,
AspectRatioType = 0x54B3,
/* ColourSpace = 0x2EB524, */
/* GammaValue = 0x2FB523, */
FrameRate = 0x2383E3,
/* end video */
/* audio */
Audio = 0xE1,
SamplingFrequency = 0xB5,
OutputSamplingFrequency = 0x78B5,
Channels = 0x9F,
/* ChannelPositions = 0x7D7B, */
BitDepth = 0x6264,
/* end audio */
/* content encoding */
/* ContentEncodings = 0x6d80, */
/* ContentEncoding = 0x6240, */
/* ContentEncodingOrder = 0x5031, */
/* ContentEncodingScope = 0x5032, */
/* ContentEncodingType = 0x5033, */
/* ContentCompression = 0x5034, */
/* ContentCompAlgo = 0x4254, */
/* ContentCompSettings = 0x4255, */
/* ContentEncryption = 0x5035, */
/* ContentEncAlgo = 0x47e1, */
/* ContentEncKeyID = 0x47e2, */
/* ContentSignature = 0x47e3, */
/* ContentSigKeyID = 0x47e4, */
/* ContentSigAlgo = 0x47e5, */
/* ContentSigHashAlgo = 0x47e6, */
/* end content encoding */
/* Cueing Data */
Cues = 0x1C53BB6B,
CuePoint = 0xBB,
CueTime = 0xB3,
CueTrackPositions = 0xB7,
CueTrack = 0xF7,
CueClusterPosition = 0xF1,
CueBlockNumber = 0x5378
/* CueCodecState = 0xEA, */
/* CueReference = 0xDB, */
/* CueRefTime = 0x96, */
/* CueRefCluster = 0x97, */
/* CueRefNumber = 0x535F, */
/* CueRefCodecState = 0xEB, */
/* Attachment */
/* Attachments = 0x1941A469, */
/* AttachedFile = 0x61A7, */
/* FileDescription = 0x467E, */
/* FileName = 0x466E, */
/* FileMimeType = 0x4660, */
/* FileData = 0x465C, */
/* FileUID = 0x46AE, */
/* FileReferral = 0x4675, */
/* Chapters */
/* Chapters = 0x1043A770, */
/* EditionEntry = 0x45B9, */
/* EditionUID = 0x45BC, */
/* EditionFlagHidden = 0x45BD, */
/* EditionFlagDefault = 0x45DB, */
/* EditionFlagOrdered = 0x45DD, */
/* ChapterAtom = 0xB6, */
/* ChapterUID = 0x73C4, */
/* ChapterTimeStart = 0x91, */
/* ChapterTimeEnd = 0x92, */
/* ChapterFlagHidden = 0x98, */
/* ChapterFlagEnabled = 0x4598, */
/* ChapterSegmentUID = 0x6E67, */
/* ChapterSegmentEditionUID = 0x6EBC, */
/* ChapterPhysicalEquiv = 0x63C3, */
/* ChapterTrack = 0x8F, */
/* ChapterTrackNumber = 0x89, */
/* ChapterDisplay = 0x80, */
/* ChapString = 0x85, */
/* ChapLanguage = 0x437C, */
/* ChapCountry = 0x437E, */
/* ChapProcess = 0x6944, */
/* ChapProcessCodecID = 0x6955, */
/* ChapProcessPrivate = 0x450D, */
/* ChapProcessCommand = 0x6911, */
/* ChapProcessTime = 0x6922, */
/* ChapProcessData = 0x6933, */
/* Tagging */
/* Tags = 0x1254C367, */
/* Tag = 0x7373, */
/* Targets = 0x63C0, */
/* TargetTypeValue = 0x68CA, */
/* TargetType = 0x63CA, */
/* Tagging_TrackUID = 0x63C5, */
/* Tagging_EditionUID = 0x63C9, */
/* Tagging_ChapterUID = 0x63C4, */
/* AttachmentUID = 0x63C6, */
/* SimpleTag = 0x67C8, */
/* TagName = 0x45A3, */
/* TagLanguage = 0x447A, */
/* TagDefault = 0x4484, */
/* TagString = 0x4487, */
/* TagBinary = 0x4485, */
};
#endif

165
media/libmkv/EbmlWriter.c Normal file
View File

@ -0,0 +1,165 @@
/*
* 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 <stdlib.h>
#include <wchar.h>
#include <string.h>
#include <limits.h>
#include "EbmlBufferWriter.h"
#if defined(_MSC_VER)
#define LITERALU64(n) n
#else
#define LITERALU64(n) n##LLU
#endif
void Ebml_WriteLen(EbmlGlobal *glob, int64_t val) {
/* TODO check and make sure we are not > than 0x0100000000000000LLU */
unsigned char size = 8; /* size in bytes to output */
/* mask to compare for byte size */
int64_t minVal = 0xff;
for (size = 1; size < 8; size ++) {
if (val < minVal)
break;
minVal = (minVal << 7);
}
val |= (((uint64_t)0x80) << ((size - 1) * 7));
Ebml_Serialize(glob, (void *) &val, sizeof(val), size);
}
void Ebml_WriteString(EbmlGlobal *glob, const char *str) {
const size_t size_ = strlen(str);
const uint64_t size = size_;
Ebml_WriteLen(glob, size);
/* TODO: it's not clear from the spec whether the nul terminator
* should be serialized too. For now we omit the null terminator.
*/
Ebml_Write(glob, str, (unsigned long)size);
}
void Ebml_WriteUTF8(EbmlGlobal *glob, const wchar_t *wstr) {
const size_t strlen = wcslen(wstr);
/* TODO: it's not clear from the spec whether the nul terminator
* should be serialized too. For now we include it.
*/
const uint64_t size = strlen;
Ebml_WriteLen(glob, size);
Ebml_Write(glob, wstr, (unsigned long)size);
}
void Ebml_WriteID(EbmlGlobal *glob, unsigned long class_id) {
int len;
if (class_id >= 0x01000000)
len = 4;
else if (class_id >= 0x00010000)
len = 3;
else if (class_id >= 0x00000100)
len = 2;
else
len = 1;
Ebml_Serialize(glob, (void *)&class_id, sizeof(class_id), len);
}
void Ebml_SerializeUnsigned32(EbmlGlobal *glob, unsigned long class_id, uint32_t ui) {
unsigned char sizeSerialized = 8 | 0x80;
Ebml_WriteID(glob, class_id);
Ebml_Serialize(glob, &sizeSerialized, sizeof(sizeSerialized), 1);
Ebml_Serialize(glob, &ui, sizeof(ui), 4);
}
void Ebml_SerializeUnsigned64(EbmlGlobal *glob, unsigned long class_id, uint64_t ui) {
unsigned char sizeSerialized = 8 | 0x80;
Ebml_WriteID(glob, class_id);
Ebml_Serialize(glob, &sizeSerialized, sizeof(sizeSerialized), 1);
Ebml_Serialize(glob, &ui, sizeof(ui), 8);
}
void Ebml_SerializeUnsigned(EbmlGlobal *glob, unsigned long class_id, unsigned long ui) {
unsigned char size = 8; /* size in bytes to output */
unsigned char sizeSerialized = 0;
unsigned long minVal;
Ebml_WriteID(glob, class_id);
minVal = 0x7fLU; /* mask to compare for byte size */
for (size = 1; size < 4; size ++) {
if (ui < minVal) {
break;
}
minVal <<= 7;
}
sizeSerialized = 0x80 | size;
Ebml_Serialize(glob, &sizeSerialized, sizeof(sizeSerialized), 1);
Ebml_Serialize(glob, &ui, sizeof(ui), size);
}
/* TODO: perhaps this is a poor name for this id serializer helper function */
void Ebml_SerializeBinary(EbmlGlobal *glob, unsigned long class_id, unsigned long bin) {
int size;
for (size = 4; size > 1; size--) {
if (bin & (unsigned int)0x000000ff << ((size - 1) * 8))
break;
}
Ebml_WriteID(glob, class_id);
Ebml_WriteLen(glob, size);
Ebml_WriteID(glob, bin);
}
void Ebml_SerializeFloat(EbmlGlobal *glob, unsigned long class_id, double d) {
unsigned char len = 0x88;
Ebml_WriteID(glob, class_id);
Ebml_Serialize(glob, &len, sizeof(len), 1);
Ebml_Serialize(glob, &d, sizeof(d), 8);
}
void Ebml_WriteSigned16(EbmlGlobal *glob, short val) {
signed long out = ((val & 0x003FFFFF) | 0x00200000) << 8;
Ebml_Serialize(glob, &out, sizeof(out), 3);
}
void Ebml_SerializeString(EbmlGlobal *glob, unsigned long class_id, const char *s) {
Ebml_WriteID(glob, class_id);
Ebml_WriteString(glob, s);
}
void Ebml_SerializeUTF8(EbmlGlobal *glob, unsigned long class_id, wchar_t *s) {
Ebml_WriteID(glob, class_id);
Ebml_WriteUTF8(glob, s);
}
void Ebml_SerializeData(EbmlGlobal *glob, unsigned long class_id, unsigned char *data, unsigned long data_length) {
Ebml_WriteID(glob, class_id);
Ebml_WriteLen(glob, data_length);
Ebml_Write(glob, data, data_length);
}
void Ebml_WriteVoid(EbmlGlobal *glob, unsigned long vSize) {
unsigned char tmp = 0;
unsigned long i = 0;
Ebml_WriteID(glob, 0xEC);
Ebml_WriteLen(glob, vSize);
for (i = 0; i < vSize; i++) {
Ebml_Write(glob, &tmp, 1);
}
}
/* TODO Serialize Date */

53
media/libmkv/EbmlWriter.h Normal file
View File

@ -0,0 +1,53 @@
/*
* 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.
*/
#ifdef __cplusplus
extern "C" {
#endif
#ifndef EBMLWRITER_HPP
#define EBMLWRITER_HPP
#include <stddef.h>
#include "vpx/vpx_integer.h"
#include "EbmlBufferWriter.h"
/* note: you must define write and serialize functions as well as your own
* EBML_GLOBAL
*
* These functions MUST be implemented
*/
// typedef struct EbmlGlobal EbmlGlobal;
// void Ebml_Serialize(EbmlGlobal *glob, const void *, int, unsigned long);
// void Ebml_Write(EbmlGlobal *glob, const void *, unsigned long);
/*****/
void Ebml_WriteLen(EbmlGlobal *glob, int64_t val);
void Ebml_WriteString(EbmlGlobal *glob, const char *str);
void Ebml_WriteUTF8(EbmlGlobal *glob, const wchar_t *wstr);
void Ebml_WriteID(EbmlGlobal *glob, unsigned long class_id);
void Ebml_SerializeUnsigned32(EbmlGlobal *glob, unsigned long class_id, uint32_t ui);
void Ebml_SerializeUnsigned64(EbmlGlobal *glob, unsigned long class_id, uint64_t ui);
void Ebml_SerializeUnsigned(EbmlGlobal *glob, unsigned long class_id, unsigned long ui);
void Ebml_SerializeBinary(EbmlGlobal *glob, unsigned long class_id, unsigned long ui);
void Ebml_SerializeFloat(EbmlGlobal *glob, unsigned long class_id, double d);
/* TODO make this more generic to signed */
void Ebml_WriteSigned16(EbmlGlobal *glob, short val);
void Ebml_SerializeString(EbmlGlobal *glob, unsigned long class_id, const char *s);
void Ebml_SerializeUTF8(EbmlGlobal *glob, unsigned long class_id, wchar_t *s);
void Ebml_SerializeData(EbmlGlobal *glob, unsigned long class_id, unsigned char *data, unsigned long data_length);
void Ebml_WriteVoid(EbmlGlobal *glob, unsigned long vSize);
/* TODO need date function */
#endif
#ifdef __cplusplus
}
#endif

31
media/libmkv/LICENSE Normal file
View File

@ -0,0 +1,31 @@
Copyright (c) 2010, The WebM Project authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of Google, nor the WebM Project, nor the names
of its contributors may be used to endorse or promote products
derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

139
media/libmkv/README Normal file
View File

@ -0,0 +1,139 @@
vpx Multi-Format Codec SDK
README - 1 August 2013
Welcome to the WebM VP8/VP9 Codec SDK!
COMPILING THE APPLICATIONS/LIBRARIES:
The build system used is similar to autotools. Building generally consists of
"configuring" with your desired build options, then using GNU make to build
the application.
1. Prerequisites
* All x86 targets require the Yasm[1] assembler be installed.
* All Windows builds require that Cygwin[2] be installed.
* Building the documentation requires PHP[3] and Doxygen[4]. If you do not
have these packages, you must pass --disable-install-docs to the
configure script.
* Downloading the data for the unit tests requires curl[5] and sha1sum.
sha1sum is provided via the GNU coreutils, installed by default on
many *nix platforms, as well as MinGW and Cygwin. If coreutils is not
available, a compatible version of sha1sum can be built from
source[6]. These requirements are optional if not running the unit
tests.
[1]: http://www.tortall.net/projects/yasm
[2]: http://www.cygwin.com
[3]: http://php.net
[4]: http://www.doxygen.org
[5]: http://curl.haxx.se
[6]: http://www.microbrew.org/tools/md5sha1sum/
2. Out-of-tree builds
Out of tree builds are a supported method of building the application. For
an out of tree build, the source tree is kept separate from the object
files produced during compilation. For instance:
$ mkdir build
$ cd build
$ ../libvpx/configure <options>
$ make
3. Configuration options
The 'configure' script supports a number of options. The --help option can be
used to get a list of supported options:
$ ../libvpx/configure --help
4. Cross development
For cross development, the most notable option is the --target option. The
most up-to-date list of supported targets can be found at the bottom of the
--help output of the configure script. As of this writing, the list of
available targets is:
armv5te-android-gcc
armv5te-linux-rvct
armv5te-linux-gcc
armv5te-none-rvct
armv6-darwin-gcc
armv6-linux-rvct
armv6-linux-gcc
armv6-none-rvct
armv7-android-gcc
armv7-darwin-gcc
armv7-linux-rvct
armv7-linux-gcc
armv7-none-rvct
armv7-win32-vs11
armv7-win32-vs12
mips32-linux-gcc
ppc32-darwin8-gcc
ppc32-darwin9-gcc
ppc32-linux-gcc
ppc64-darwin8-gcc
ppc64-darwin9-gcc
ppc64-linux-gcc
sparc-solaris-gcc
x86-android-gcc
x86-darwin8-gcc
x86-darwin8-icc
x86-darwin9-gcc
x86-darwin9-icc
x86-darwin10-gcc
x86-darwin11-gcc
x86-darwin12-gcc
x86-darwin13-gcc
x86-linux-gcc
x86-linux-icc
x86-os2-gcc
x86-solaris-gcc
x86-win32-gcc
x86-win32-vs7
x86-win32-vs8
x86-win32-vs9
x86-win32-vs10
x86-win32-vs11
x86-win32-vs12
x86_64-darwin9-gcc
x86_64-darwin10-gcc
x86_64-darwin11-gcc
x86_64-darwin12-gcc
x86_64-darwin13-gcc
x86_64-linux-gcc
x86_64-linux-icc
x86_64-solaris-gcc
x86_64-win64-gcc
x86_64-win64-vs8
x86_64-win64-vs9
x86_64-win64-vs10
x86_64-win64-vs11
x86_64-win64-vs12
universal-darwin8-gcc
universal-darwin9-gcc
universal-darwin10-gcc
universal-darwin11-gcc
universal-darwin12-gcc
universal-darwin13-gcc
generic-gnu
The generic-gnu target, in conjunction with the CROSS environment variable,
can be used to cross compile architectures that aren't explicitly listed, if
the toolchain is a cross GNU (gcc/binutils) toolchain. Other POSIX toolchains
will likely work as well. For instance, to build using the mipsel-linux-uclibc
toolchain, the following command could be used (note, POSIX SH syntax, adapt
to your shell as necessary):
$ CROSS=mipsel-linux-uclibc- ../libvpx/configure
In addition, the executables to be invoked can be overridden by specifying the
environment variables: CC, AR, LD, AS, STRIP, NM. Additional flags can be
passed to these executables with CFLAGS, LDFLAGS, and ASFLAGS.
5. Configuration errors
If the configuration step fails, the first step is to look in the error log.
This defaults to config.log. This should give a good indication of what went
wrong. If not, contact us for support.
SUPPORT
This library is an open source project supported by its community. Please
please email webm-discuss@webmproject.org for help.

View File

@ -0,0 +1,6 @@
The source from this directory was copied from the libvpx/third_party/libmkv
git repository using the update.sh script.
The libvpx git repository is: http://git.chromium.org/webm/libvpx.git
The git commit ID used was c5aaf923d80e9f71e0c93d7d99dc1e2f83d7acbf.

219
media/libmkv/WebMElement.c Normal file
View File

@ -0,0 +1,219 @@
// 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 "EbmlIDs.h"
#include "WebMElement.h"
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <time.h>
#define kVorbisPrivateMaxSize 4000
#define UInt64 uint64_t
void writeHeader(EbmlGlobal *glob) {
EbmlLoc start;
Ebml_StartSubElement(glob, &start, EBML);
Ebml_SerializeUnsigned(glob, EBMLVersion, 1);
Ebml_SerializeUnsigned(glob, EBMLReadVersion, 1); // EBML Read Version
Ebml_SerializeUnsigned(glob, EBMLMaxIDLength, 4); // EBML Max ID Length
Ebml_SerializeUnsigned(glob, EBMLMaxSizeLength, 8); // EBML Max Size Length
Ebml_SerializeString(glob, DocType, "webm"); // Doc Type
Ebml_SerializeUnsigned(glob, DocTypeVersion, 2); // Doc Type Version
Ebml_SerializeUnsigned(glob, DocTypeReadVersion, 2); // Doc Type Read Version
Ebml_EndSubElement(glob, &start);
}
void writeSimpleBlock(EbmlGlobal *glob, unsigned char trackNumber, short timeCode,
int isKeyframe, unsigned char lacingFlag, int discardable,
unsigned char *data, unsigned long dataLength) {
unsigned long blockLength = 4 + dataLength;
unsigned char flags = 0x00 | (isKeyframe ? 0x80 : 0x00) | (lacingFlag << 1) | discardable;
Ebml_WriteID(glob, SimpleBlock);
blockLength |= 0x10000000; // TODO check length < 0x0FFFFFFFF
Ebml_Serialize(glob, &blockLength, sizeof(blockLength), 4);
trackNumber |= 0x80; // TODO check track nubmer < 128
Ebml_Write(glob, &trackNumber, 1);
// Ebml_WriteSigned16(glob, timeCode,2); //this is 3 bytes
Ebml_Serialize(glob, &timeCode, sizeof(timeCode), 2);
flags = 0x00 | (isKeyframe ? 0x80 : 0x00) | (lacingFlag << 1) | discardable;
Ebml_Write(glob, &flags, 1);
Ebml_Write(glob, data, dataLength);
}
static UInt64 generateTrackID(unsigned int trackNumber) {
UInt64 t = time(NULL) * trackNumber;
UInt64 r = rand();
r = r << 32;
r += rand();
// UInt64 rval = t ^ r;
return t ^ r;
}
void writeVideoTrack(EbmlGlobal *glob, unsigned int trackNumber, int flagLacing,
char *codecId, unsigned int pixelWidth, unsigned int pixelHeight,
double frameRate) {
EbmlLoc start;
UInt64 trackID;
Ebml_StartSubElement(glob, &start, TrackEntry);
Ebml_SerializeUnsigned(glob, TrackNumber, trackNumber);
trackID = generateTrackID(trackNumber);
Ebml_SerializeUnsigned(glob, TrackUID, trackID);
Ebml_SerializeString(glob, CodecName, "VP8"); // TODO shouldn't be fixed
Ebml_SerializeUnsigned(glob, TrackType, 1); // video is always 1
Ebml_SerializeString(glob, CodecID, codecId);
{
EbmlLoc videoStart;
Ebml_StartSubElement(glob, &videoStart, Video);
Ebml_SerializeUnsigned(glob, PixelWidth, pixelWidth);
Ebml_SerializeUnsigned(glob, PixelHeight, pixelHeight);
Ebml_SerializeFloat(glob, FrameRate, frameRate);
Ebml_EndSubElement(glob, &videoStart); // Video
}
Ebml_EndSubElement(glob, &start); // Track Entry
}
void writeAudioTrack(EbmlGlobal *glob, unsigned int trackNumber, int flagLacing,
char *codecId, double samplingFrequency, unsigned int channels,
unsigned char *private, unsigned long privateSize) {
EbmlLoc start;
UInt64 trackID;
Ebml_StartSubElement(glob, &start, TrackEntry);
Ebml_SerializeUnsigned(glob, TrackNumber, trackNumber);
trackID = generateTrackID(trackNumber);
Ebml_SerializeUnsigned(glob, TrackUID, trackID);
Ebml_SerializeUnsigned(glob, TrackType, 2); // audio is always 2
// I am using defaults for thesed required fields
/* Ebml_SerializeUnsigned(glob, FlagEnabled, 1);
Ebml_SerializeUnsigned(glob, FlagDefault, 1);
Ebml_SerializeUnsigned(glob, FlagForced, 1);
Ebml_SerializeUnsigned(glob, FlagLacing, flagLacing);*/
Ebml_SerializeString(glob, CodecID, codecId);
Ebml_SerializeData(glob, CodecPrivate, private, privateSize);
Ebml_SerializeString(glob, CodecName, "VORBIS"); // fixed for now
{
EbmlLoc AudioStart;
Ebml_StartSubElement(glob, &AudioStart, Audio);
Ebml_SerializeFloat(glob, SamplingFrequency, samplingFrequency);
Ebml_SerializeUnsigned(glob, Channels, channels);
Ebml_EndSubElement(glob, &AudioStart);
}
Ebml_EndSubElement(glob, &start);
}
void writeSegmentInformation(EbmlGlobal *ebml, EbmlLoc *startInfo, unsigned long timeCodeScale, double duration) {
Ebml_StartSubElement(ebml, startInfo, Info);
Ebml_SerializeUnsigned(ebml, TimecodeScale, timeCodeScale);
Ebml_SerializeFloat(ebml, Segment_Duration, duration * 1000.0); // Currently fixed to using milliseconds
Ebml_SerializeString(ebml, 0x4D80, "QTmuxingAppLibWebM-0.0.1");
Ebml_SerializeString(ebml, 0x5741, "QTwritingAppLibWebM-0.0.1");
Ebml_EndSubElement(ebml, startInfo);
}
/*
void Mkv_InitializeSegment(Ebml& ebml_out, EbmlLoc& ebmlLoc)
{
Ebml_StartSubElement(ebml_out, ebmlLoc, 0x18538067);
}
void Mkv_InitializeSeek(Ebml& ebml_out, EbmlLoc& ebmlLoc)
{
Ebml_StartSubElement(ebml_out, ebmlLoc, 0x114d9b74);
}
void Mkv_WriteSeekInformation(Ebml& ebml_out, SeekStruct& seekInformation)
{
EbmlLoc ebmlLoc;
Ebml_StartSubElement(ebml_out, ebmlLoc, 0x4dbb);
Ebml_SerializeString(ebml_out, 0x53ab, seekInformation.SeekID);
Ebml_SerializeUnsigned(ebml_out, 0x53ac, seekInformation.SeekPosition);
Ebml_EndSubElement(ebml_out, ebmlLoc);
}
void Mkv_WriteSegmentInformation(Ebml& ebml_out, SegmentInformationStruct& segmentInformation)
{
Ebml_SerializeUnsigned(ebml_out, 0x73a4, segmentInformation.segmentUID);
if (segmentInformation.filename != 0)
Ebml_SerializeString(ebml_out, 0x7384, segmentInformation.filename);
Ebml_SerializeUnsigned(ebml_out, 0x2AD7B1, segmentInformation.TimecodeScale);
Ebml_SerializeUnsigned(ebml_out, 0x4489, segmentInformation.Duration);
// TODO date
Ebml_SerializeWString(ebml_out, 0x4D80, L"MKVMUX");
Ebml_SerializeWString(ebml_out, 0x5741, segmentInformation.WritingApp);
}
void Mkv_InitializeTrack(Ebml& ebml_out, EbmlLoc& ebmlLoc)
{
Ebml_StartSubElement(ebml_out, ebmlLoc, 0x1654AE6B);
}
static void Mkv_WriteGenericTrackData(Ebml& ebml_out, TrackStruct& track)
{
Ebml_SerializeUnsigned(ebml_out, 0xD7, track.TrackNumber);
Ebml_SerializeUnsigned(ebml_out, 0x73C5, track.TrackUID);
Ebml_SerializeUnsigned(ebml_out, 0x83, track.TrackType);
Ebml_SerializeUnsigned(ebml_out, 0xB9, track.FlagEnabled ? 1 :0);
Ebml_SerializeUnsigned(ebml_out, 0x88, track.FlagDefault ? 1 :0);
Ebml_SerializeUnsigned(ebml_out, 0x55AA, track.FlagForced ? 1 :0);
if (track.Language != 0)
Ebml_SerializeString(ebml_out, 0x22B59C, track.Language);
if (track.CodecID != 0)
Ebml_SerializeString(ebml_out, 0x86, track.CodecID);
if (track.CodecPrivate != 0)
Ebml_SerializeData(ebml_out, 0x63A2, track.CodecPrivate, track.CodecPrivateLength);
if (track.CodecName != 0)
Ebml_SerializeWString(ebml_out, 0x258688, track.CodecName);
}
void Mkv_WriteVideoTrack(Ebml& ebml_out, TrackStruct & track, VideoTrackStruct& video)
{
EbmlLoc trackHeadLoc, videoHeadLoc;
Ebml_StartSubElement(ebml_out, trackHeadLoc, 0xAE); // start Track
Mkv_WriteGenericTrackData(ebml_out, track);
Ebml_StartSubElement(ebml_out, videoHeadLoc, 0xE0); // start Video
Ebml_SerializeUnsigned(ebml_out, 0x9A, video.FlagInterlaced ? 1 :0);
Ebml_SerializeUnsigned(ebml_out, 0xB0, video.PixelWidth);
Ebml_SerializeUnsigned(ebml_out, 0xBA, video.PixelHeight);
Ebml_SerializeUnsigned(ebml_out, 0x54B0, video.PixelDisplayWidth);
Ebml_SerializeUnsigned(ebml_out, 0x54BA, video.PixelDisplayHeight);
Ebml_SerializeUnsigned(ebml_out, 0x54B2, video.displayUnit);
Ebml_SerializeFloat(ebml_out, 0x2383E3, video.FrameRate);
Ebml_EndSubElement(ebml_out, videoHeadLoc);
Ebml_EndSubElement(ebml_out, trackHeadLoc);
}
void Mkv_WriteAudioTrack(Ebml& ebml_out, TrackStruct & track, AudioTrackStruct& video)
{
EbmlLoc trackHeadLoc, audioHeadLoc;
Ebml_StartSubElement(ebml_out, trackHeadLoc, 0xAE);
Mkv_WriteGenericTrackData(ebml_out, track);
Ebml_StartSubElement(ebml_out, audioHeadLoc, 0xE0); // start Audio
Ebml_SerializeFloat(ebml_out, 0xB5, video.SamplingFrequency);
Ebml_SerializeUnsigned(ebml_out, 0x9F, video.Channels);
Ebml_SerializeUnsigned(ebml_out, 0x6264, video.BitDepth);
Ebml_EndSubElement(ebml_out, audioHeadLoc); // end audio
Ebml_EndSubElement(ebml_out, trackHeadLoc);
}
void Mkv_WriteEbmlClusterHead(Ebml& ebml_out, EbmlLoc& ebmlLoc, ClusterHeadStruct & clusterHead)
{
Ebml_StartSubElement(ebml_out, ebmlLoc, 0x1F43B675);
Ebml_SerializeUnsigned(ebml_out, 0x6264, clusterHead.TimeCode);
}
void Mkv_WriteSimpleBlockHead(Ebml& ebml_out, EbmlLoc& ebmlLoc, SimpleBlockStruct& block)
{
Ebml_StartSubElement(ebml_out, ebmlLoc, 0xA3);
Ebml_Write1UInt(ebml_out, block.TrackNumber);
Ebml_WriteSigned16(ebml_out,block.TimeCode);
unsigned char flags = 0x00 | (block.iskey ? 0x80:0x00) | (block.lacing << 1) | block.discardable;
Ebml_Write1UInt(ebml_out, flags); // TODO this may be the wrong function
Ebml_Serialize(ebml_out, block.data, block.dataLength);
Ebml_EndSubElement(ebml_out,ebmlLoc);
}
*/

View File

@ -0,0 +1,37 @@
// 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.
#ifdef __cplusplus
extern "C" {
#endif
#ifndef MKV_CONTEXT_HPP
#define MKV_CONTEXT_HPP 1
#include "EbmlWriter.h"
// these are helper functions
void writeHeader(EbmlGlobal *ebml);
void writeSegmentInformation(EbmlGlobal *ebml, EbmlLoc *startInfo, unsigned long timeCodeScale, double duration);
// this function is a helper only, it assumes a lot of defaults
void writeVideoTrack(EbmlGlobal *ebml, unsigned int trackNumber, int flagLacing,
char *codecId, unsigned int pixelWidth, unsigned int pixelHeight,
double frameRate);
void writeAudioTrack(EbmlGlobal *glob, unsigned int trackNumber, int flagLacing,
char *codecId, double samplingFrequency, unsigned int channels,
unsigned char *private_, unsigned long privateSize);
void writeSimpleBlock(EbmlGlobal *ebml, unsigned char trackNumber, short timeCode,
int isKeyframe, unsigned char lacingFlag, int discardable,
unsigned char *data, unsigned long dataLength);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,133 @@
diff --git a/EbmlBufferWriter.h b/EbmlBufferWriter.h
index c135f29..d5116ce 100644
--- a/EbmlBufferWriter.h
+++ b/EbmlBufferWriter.h
@@ -11,6 +11,9 @@ typedef struct {
unsigned int offset;
} EbmlGlobal;
+void Ebml_Write(EbmlGlobal *glob, const void *buffer_in, unsigned long len);
+void Ebml_Serialize(EbmlGlobal *glob, const void *buffer_in,
+ int buffer_size, unsigned long len);
void Ebml_StartSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc, unsigned long class_id);
void Ebml_EndSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc);
diff --git a/EbmlIDs.h b/EbmlIDs.h
index 44d4385..3b5da19 100644
--- a/EbmlIDs.h
+++ b/EbmlIDs.h
@@ -119,7 +119,7 @@ enum mkv {
/* video */
Video = 0xE0,
FlagInterlaced = 0x9A,
- StereoMode = 0x53B8,
+ WEBM_StereoMode = 0x53B8,
AlphaMode = 0x53C0,
PixelWidth = 0xB0,
PixelHeight = 0xBA,
diff --git a/EbmlWriter.c b/EbmlWriter.c
index ebefc1a..087e817 100644
--- a/EbmlWriter.c
+++ b/EbmlWriter.c
@@ -12,6 +12,7 @@
#include <wchar.h>
#include <string.h>
#include <limits.h>
+#include "EbmlBufferWriter.h"
#if defined(_MSC_VER)
#define LITERALU64(n) n
#else
diff --git a/EbmlWriter.h b/EbmlWriter.h
index a0a848b..3aee2b3 100644
--- a/EbmlWriter.h
+++ b/EbmlWriter.h
@@ -7,10 +7,16 @@
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#ifndef EBMLWRITER_HPP
#define EBMLWRITER_HPP
#include <stddef.h>
#include "vpx/vpx_integer.h"
+#include "EbmlBufferWriter.h"
/* note: you must define write and serialize functions as well as your own
* EBML_GLOBAL
@@ -18,9 +24,9 @@
* These functions MUST be implemented
*/
-typedef struct EbmlGlobal EbmlGlobal;
-void Ebml_Serialize(EbmlGlobal *glob, const void *, int, unsigned long);
-void Ebml_Write(EbmlGlobal *glob, const void *, unsigned long);
+// typedef struct EbmlGlobal EbmlGlobal;
+// void Ebml_Serialize(EbmlGlobal *glob, const void *, int, unsigned long);
+// void Ebml_Write(EbmlGlobal *glob, const void *, unsigned long);
/*****/
@@ -41,3 +47,7 @@ void Ebml_SerializeData(EbmlGlobal *glob, unsigned long class_id, unsigned char
void Ebml_WriteVoid(EbmlGlobal *glob, unsigned long vSize);
/* TODO need date function */
#endif
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/WebMElement.c b/WebMElement.c
index 02eefa4..0d5056d 100644
--- a/WebMElement.c
+++ b/WebMElement.c
@@ -6,8 +6,6 @@
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
-
-#include "EbmlBufferWriter.h"
#include "EbmlIDs.h"
#include "WebMElement.h"
#include <stdio.h>
diff --git a/WebMElement.h b/WebMElement.h
index d9ad0a0..987582a 100644
--- a/WebMElement.h
+++ b/WebMElement.h
@@ -6,10 +6,15 @@
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
+#ifdef __cplusplus
+extern "C" {
+#endif
#ifndef MKV_CONTEXT_HPP
#define MKV_CONTEXT_HPP 1
+#include "EbmlWriter.h"
+
void writeSimpleBock(EbmlGlobal *ebml, unsigned char trackNumber, unsigned short timeCode,
int isKeyframe, unsigned char lacingFlag, int discardable,
unsigned char *data, unsigned long dataLength);
@@ -24,12 +29,14 @@ void writeVideoTrack(EbmlGlobal *ebml, unsigned int trackNumber, int flagLacing,
double frameRate);
void writeAudioTrack(EbmlGlobal *glob, unsigned int trackNumber, int flagLacing,
char *codecId, double samplingFrequency, unsigned int channels,
- unsigned char *private, unsigned long privateSize);
+ unsigned char *private_, unsigned long privateSize);
void writeSimpleBlock(EbmlGlobal *ebml, unsigned char trackNumber, short timeCode,
int isKeyframe, unsigned char lacingFlag, int discardable,
unsigned char *data, unsigned long dataLength);
+#endif
-
-#endif
\ No newline at end of file
+#ifdef __cplusplus
+}
+#endif

27
media/libmkv/moz.build Normal file
View File

@ -0,0 +1,27 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
EXPORTS.libmkv += [
'EbmlBufferWriter.h',
'EbmlIDs.h',
'EbmlWriter.h',
'WebMElement.h',
]
UNIFIED_SOURCES += [
]
# These files can't be unified because of function redefinitions.
SOURCES += [
'EbmlBufferWriter.c',
'EbmlWriter.c',
'WebMElement.c',
]
if CONFIG['GKMEDIAS_SHARED_LIBRARY']:
NO_VISIBILITY_FLAGS = True
FINAL_LIBRARY = 'gkmedias'

View File

@ -0,0 +1,193 @@
diff --git a/EbmlBufferWriter.c b/EbmlBufferWriter.c
index 574e478..8c26e80 100644
--- a/EbmlBufferWriter.c
+++ b/EbmlBufferWriter.c
@@ -8,6 +8,31 @@
#include <wchar.h>
#include <string.h>
+void
+Ebml_Serialize(EbmlGlobal *glob, const void *buffer_in, int buffer_size, unsigned long len)
+{
+ /* buffer_size:
+ * 1 - int8_t;
+ * 2 - int16_t;
+ * 3 - int32_t;
+ * 4 - int64_t;
+ */
+ long i;
+ for(i = len-1; i >= 0; i--) {
+ unsigned char x;
+ if (buffer_size == 1) {
+ x = (char)(*(const int8_t *)buffer_in >> (i * 8));
+ } else if (buffer_size == 2) {
+ x = (char)(*(const int16_t *)buffer_in >> (i * 8));
+ } else if (buffer_size == 4) {
+ x = (char)(*(const int32_t *)buffer_in >> (i * 8));
+ } else if (buffer_size == 8) {
+ x = (char)(*(const int64_t *)buffer_in >> (i * 8));
+ }
+ Ebml_Write(glob, &x, 1);
+ }
+}
+
void Ebml_Write(EbmlGlobal *glob, const void *buffer_in, unsigned long len) {
unsigned char *src = glob->buf;
src += glob->offset;
@@ -19,12 +44,12 @@ static void _Serialize(EbmlGlobal *glob, const unsigned char *p, const unsigned
while (q != p) {
--q;
- unsigned long cbWritten;
memcpy(&(glob->buf[glob->offset]), q, 1);
glob->offset++;
}
}
+/*
void Ebml_Serialize(EbmlGlobal *glob, const void *buffer_in, unsigned long len) {
// assert(buf);
@@ -33,22 +58,22 @@ void Ebml_Serialize(EbmlGlobal *glob, const void *buffer_in, unsigned long len)
_Serialize(glob, p, q);
}
-
+*/
void Ebml_StartSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc, unsigned long class_id) {
+ unsigned long long unknownLen = 0x01FFFFFFFFFFFFFFLL;
Ebml_WriteID(glob, class_id);
ebmlLoc->offset = glob->offset;
// todo this is always taking 8 bytes, this may need later optimization
- unsigned long long unknownLen = 0x01FFFFFFFFFFFFFFLLU;
- Ebml_Serialize(glob, (void *)&unknownLen, 8); // this is a key that says lenght unknown
+ Ebml_Serialize(glob, (void *)&unknownLen,sizeof(unknownLen), 8); // this is a key that says lenght unknown
}
void Ebml_EndSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc) {
unsigned long long size = glob->offset - ebmlLoc->offset - 8;
unsigned long long curOffset = glob->offset;
glob->offset = ebmlLoc->offset;
- size |= 0x0100000000000000LLU;
- Ebml_Serialize(glob, &size, 8);
+ size |= 0x0100000000000000LL;
+ Ebml_Serialize(glob, &size,sizeof(size), 8);
glob->offset = curOffset;
}
diff --git a/EbmlBufferWriter.h b/EbmlBufferWriter.h
index acd5c2a..c135f29 100644
--- a/EbmlBufferWriter.h
+++ b/EbmlBufferWriter.h
@@ -11,9 +11,7 @@ typedef struct {
unsigned int offset;
} EbmlGlobal;
-
void Ebml_StartSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc, unsigned long class_id);
void Ebml_EndSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc);
-
#endif
diff --git a/EbmlWriter.c b/EbmlWriter.c
index 27cfe86..ebefc1a 100644
--- a/EbmlWriter.c
+++ b/EbmlWriter.c
@@ -74,6 +74,13 @@ void Ebml_WriteID(EbmlGlobal *glob, unsigned long class_id) {
Ebml_Serialize(glob, (void *)&class_id, sizeof(class_id), len);
}
+void Ebml_SerializeUnsigned32(EbmlGlobal *glob, unsigned long class_id, uint32_t ui) {
+ unsigned char sizeSerialized = 8 | 0x80;
+ Ebml_WriteID(glob, class_id);
+ Ebml_Serialize(glob, &sizeSerialized, sizeof(sizeSerialized), 1);
+ Ebml_Serialize(glob, &ui, sizeof(ui), 4);
+}
+
void Ebml_SerializeUnsigned64(EbmlGlobal *glob, unsigned long class_id, uint64_t ui) {
unsigned char sizeSerialized = 8 | 0x80;
Ebml_WriteID(glob, class_id);
diff --git a/EbmlWriter.h b/EbmlWriter.h
index b94f757..a0a848b 100644
--- a/EbmlWriter.h
+++ b/EbmlWriter.h
@@ -28,6 +28,7 @@ void Ebml_WriteLen(EbmlGlobal *glob, int64_t val);
void Ebml_WriteString(EbmlGlobal *glob, const char *str);
void Ebml_WriteUTF8(EbmlGlobal *glob, const wchar_t *wstr);
void Ebml_WriteID(EbmlGlobal *glob, unsigned long class_id);
+void Ebml_SerializeUnsigned32(EbmlGlobal *glob, unsigned long class_id, uint32_t ui);
void Ebml_SerializeUnsigned64(EbmlGlobal *glob, unsigned long class_id, uint64_t ui);
void Ebml_SerializeUnsigned(EbmlGlobal *glob, unsigned long class_id, unsigned long ui);
void Ebml_SerializeBinary(EbmlGlobal *glob, unsigned long class_id, unsigned long ui);
diff --git a/WebMElement.c b/WebMElement.c
index 2f79a3c..02eefa4 100644
--- a/WebMElement.c
+++ b/WebMElement.c
@@ -11,8 +11,12 @@
#include "EbmlIDs.h"
#include "WebMElement.h"
#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <time.h>
#define kVorbisPrivateMaxSize 4000
+#define UInt64 uint64_t
void writeHeader(EbmlGlobal *glob) {
EbmlLoc start;
@@ -30,15 +34,16 @@ void writeHeader(EbmlGlobal *glob) {
void writeSimpleBlock(EbmlGlobal *glob, unsigned char trackNumber, short timeCode,
int isKeyframe, unsigned char lacingFlag, int discardable,
unsigned char *data, unsigned long dataLength) {
- Ebml_WriteID(glob, SimpleBlock);
unsigned long blockLength = 4 + dataLength;
+ unsigned char flags = 0x00 | (isKeyframe ? 0x80 : 0x00) | (lacingFlag << 1) | discardable;
+ Ebml_WriteID(glob, SimpleBlock);
blockLength |= 0x10000000; // TODO check length < 0x0FFFFFFFF
Ebml_Serialize(glob, &blockLength, sizeof(blockLength), 4);
trackNumber |= 0x80; // TODO check track nubmer < 128
Ebml_Write(glob, &trackNumber, 1);
// Ebml_WriteSigned16(glob, timeCode,2); //this is 3 bytes
Ebml_Serialize(glob, &timeCode, sizeof(timeCode), 2);
- unsigned char flags = 0x00 | (isKeyframe ? 0x80 : 0x00) | (lacingFlag << 1) | discardable;
+ flags = 0x00 | (isKeyframe ? 0x80 : 0x00) | (lacingFlag << 1) | discardable;
Ebml_Write(glob, &flags, 1);
Ebml_Write(glob, data, dataLength);
}
@@ -48,17 +53,18 @@ static UInt64 generateTrackID(unsigned int trackNumber) {
UInt64 r = rand();
r = r << 32;
r += rand();
- UInt64 rval = t ^ r;
- return rval;
+// UInt64 rval = t ^ r;
+ return t ^ r;
}
void writeVideoTrack(EbmlGlobal *glob, unsigned int trackNumber, int flagLacing,
char *codecId, unsigned int pixelWidth, unsigned int pixelHeight,
double frameRate) {
EbmlLoc start;
+ UInt64 trackID;
Ebml_StartSubElement(glob, &start, TrackEntry);
Ebml_SerializeUnsigned(glob, TrackNumber, trackNumber);
- UInt64 trackID = generateTrackID(trackNumber);
+ trackID = generateTrackID(trackNumber);
Ebml_SerializeUnsigned(glob, TrackUID, trackID);
Ebml_SerializeString(glob, CodecName, "VP8"); // TODO shouldn't be fixed
@@ -78,9 +84,10 @@ void writeAudioTrack(EbmlGlobal *glob, unsigned int trackNumber, int flagLacing,
char *codecId, double samplingFrequency, unsigned int channels,
unsigned char *private, unsigned long privateSize) {
EbmlLoc start;
+ UInt64 trackID;
Ebml_StartSubElement(glob, &start, TrackEntry);
Ebml_SerializeUnsigned(glob, TrackNumber, trackNumber);
- UInt64 trackID = generateTrackID(trackNumber);
+ trackID = generateTrackID(trackNumber);
Ebml_SerializeUnsigned(glob, TrackUID, trackID);
Ebml_SerializeUnsigned(glob, TrackType, 2); // audio is always 2
// I am using defaults for thesed required fields

33
media/libmkv/update.sh Normal file
View File

@ -0,0 +1,33 @@
# Usage: sh update.sh <upstream_src_directory>
set -e
echo "copy source from libvpx"
cp $1/third_party/libmkv/EbmlBufferWriter.c .
cp $1/third_party/libmkv/WebMElement.c .
cp $1/third_party/libmkv/EbmlWriter.c .
cp $1/third_party/libmkv/EbmlWriter.h .
cp $1/third_party/libmkv/EbmlBufferWriter.h .
cp $1/third_party/libmkv/WebMElement.h .
cp $1/third_party/libmkv/EbmlIDs.h .
cp $1/LICENSE .
cp $1/README .
cp $1/AUTHORS .
if [ -d $1/.git ]; then
rev=$(cd $1 && git rev-parse --verify HEAD)
dirty=$(cd $1 && git diff-index --name-only HEAD)
fi
if [ -n "$rev" ]; then
version=$rev
if [ -n "$dirty" ]; then
version=$version-dirty
echo "WARNING: updating from a dirty git repository."
fi
sed -i.bak -e "/The git commit ID used was/ s/[0-9a-f]\{40\}\(-dirty\)\{0,1\}\./$version./" README_MOZILLA
rm README_MOZILLA.bak
else
echo "Remember to update README_MOZILLA with the version details."
fi
echo "please apply source_fix.patch and gecko_fix.patch"