mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge b2g-inbound to m-c.
This commit is contained in:
commit
c35da6fdf3
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
"revision": "c5f8db7e1e71a9bfe0d29665d2b4cf3ae773094e",
|
||||
"revision": "1150c11d1e6f0f78df3552dfca8c53d5ed5c173d",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -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
|
||||
|
||||
|
3
config/external/moz.build
vendored
3
config/external/moz.build
vendored
@ -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']
|
||||
|
||||
|
@ -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 ==================================
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
472
content/media/encoder/VP8TrackEncoder.cpp
Normal file
472
content/media/encoder/VP8TrackEncoder.cpp
Normal 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
|
93
content/media/encoder/VP8TrackEncoder.h
Normal file
93
content/media/encoder/VP8TrackEncoder.h
Normal 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
|
238
content/media/encoder/VorbisTrackEncoder.cpp
Normal file
238
content/media/encoder/VorbisTrackEncoder.cpp
Normal 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
|
54
content/media/encoder/VorbisTrackEncoder.h
Normal file
54
content/media/encoder/VorbisTrackEncoder.h
Normal 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
|
@ -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
|
||||
|
||||
|
@ -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]
|
||||
|
90
content/media/test/test_mediarecorder_unsupported_src.html
Normal file
90
content/media/test/test_mediarecorder_unsupported_src.html
Normal 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>
|
177
content/media/webm/EbmlComposer.cpp
Normal file
177
content/media/webm/EbmlComposer.cpp
Normal 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)
|
||||
{}
|
||||
|
||||
}
|
75
content/media/webm/EbmlComposer.h
Normal file
75
content/media/webm/EbmlComposer.h
Normal 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
|
64
content/media/webm/WebMWriter.cpp
Normal file
64
content/media/webm/WebMWriter.cpp
Normal 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
|
70
content/media/webm/WebMWriter.h
Normal file
70
content/media/webm/WebMWriter.h
Normal 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
|
@ -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'
|
||||
|
42
dom/bluetooth/bluedroid/b2g_bdroid_buildcfg.h
Normal file
42
dom/bluetooth/bluedroid/b2g_bdroid_buildcfg.h
Normal 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 */
|
@ -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);
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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
100
media/libmkv/AUTHORS
Normal 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
|
79
media/libmkv/EbmlBufferWriter.c
Normal file
79
media/libmkv/EbmlBufferWriter.c
Normal 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;
|
||||
}
|
||||
|
20
media/libmkv/EbmlBufferWriter.h
Normal file
20
media/libmkv/EbmlBufferWriter.h
Normal 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
231
media/libmkv/EbmlIDs.h
Normal 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
165
media/libmkv/EbmlWriter.c
Normal 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
53
media/libmkv/EbmlWriter.h
Normal 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
31
media/libmkv/LICENSE
Normal 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
139
media/libmkv/README
Normal 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.
|
||||
|
6
media/libmkv/README_MOZILLA
Normal file
6
media/libmkv/README_MOZILLA
Normal 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
219
media/libmkv/WebMElement.c
Normal 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);
|
||||
}
|
||||
*/
|
37
media/libmkv/WebMElement.h
Normal file
37
media/libmkv/WebMElement.h
Normal 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
|
133
media/libmkv/gecko_fix.patch
Normal file
133
media/libmkv/gecko_fix.patch
Normal 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
27
media/libmkv/moz.build
Normal 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'
|
193
media/libmkv/source_fix.patch
Normal file
193
media/libmkv/source_fix.patch
Normal 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
33
media/libmkv/update.sh
Normal 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"
|
Loading…
Reference in New Issue
Block a user