mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 03:15:11 +00:00
Merge autoland to m-c. a=merge
This commit is contained in:
commit
14b640ba33
@ -2,11 +2,11 @@
|
||||
|
||||
function* sendMessage(options) {
|
||||
function background(options) {
|
||||
browser.runtime.sendMessage("invalid-extension-id", {}, {}, result => {
|
||||
browser.runtime.sendMessage(result => {
|
||||
browser.test.assertEq(undefined, result, "Argument value");
|
||||
if (options.checkLastError) {
|
||||
let lastError = browser[options.checkLastError].lastError;
|
||||
browser.test.assertEq("Invalid extension ID",
|
||||
browser.test.assertEq("runtime.sendMessage's message argument is missing",
|
||||
lastError && lastError.message,
|
||||
"lastError value");
|
||||
}
|
||||
@ -34,7 +34,7 @@ add_task(function* testLastError() {
|
||||
// checked.
|
||||
for (let api of ["extension", "runtime"]) {
|
||||
let waitForConsole = new Promise(resolve => {
|
||||
SimpleTest.monitorConsole(resolve, [{message: /Invalid extension ID/, forbid: true}]);
|
||||
SimpleTest.monitorConsole(resolve, [{message: /message argument is missing/, forbid: true}]);
|
||||
});
|
||||
|
||||
yield sendMessage({checkLastError: api});
|
||||
@ -45,7 +45,7 @@ add_task(function* testLastError() {
|
||||
|
||||
// Check that we do have a console message when lastError is not checked.
|
||||
let waitForConsole = new Promise(resolve => {
|
||||
SimpleTest.monitorConsole(resolve, [{message: /Unchecked lastError value: Error: Invalid extension ID/}]);
|
||||
SimpleTest.monitorConsole(resolve, [{message: /Unchecked lastError value: Error: runtime.sendMessage's message argument is missing/}]);
|
||||
});
|
||||
|
||||
yield sendMessage({});
|
||||
|
32
configure.py
32
configure.py
@ -10,6 +10,8 @@ import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from collections import Iterable
|
||||
|
||||
|
||||
base_dir = os.path.abspath(os.path.dirname(__file__))
|
||||
sys.path.insert(0, os.path.join(base_dir, 'python', 'mozbuild'))
|
||||
@ -79,14 +81,36 @@ if __name__ == '__main__':
|
||||
config_status(**args)
|
||||
''')
|
||||
|
||||
# Running config.status standalone uses byte literals for all the config,
|
||||
# instead of the unicode literals we have in sanitized_config right now.
|
||||
# Some values in sanitized_config also have more complex types, such as
|
||||
# EnumString, which using when calling config_status would currently break
|
||||
# the build, as well as making it inconsistent with re-running
|
||||
# config.status. Fortunately, EnumString derives from unicode, so it's
|
||||
# covered by converting unicode strings.
|
||||
# Moreover, a lot of the build backend code is currently expecting byte
|
||||
# strings and breaks in subtle ways with unicode strings.
|
||||
def encode(v):
|
||||
if isinstance(v, dict):
|
||||
return {
|
||||
encode(k): encode(val)
|
||||
for k, val in v.iteritems()
|
||||
}
|
||||
if isinstance(v, str):
|
||||
return v
|
||||
if isinstance(v, unicode):
|
||||
return v.encode(encoding)
|
||||
if isinstance(v, Iterable):
|
||||
return [encode(i) for i in v]
|
||||
return v
|
||||
|
||||
# Other things than us are going to run this file, so we need to give it
|
||||
# executable permissions.
|
||||
os.chmod('config.status', 0o755)
|
||||
if config.get('MOZ_BUILD_APP') != 'js' or config.get('JS_STANDALONE'):
|
||||
os.environ['WRITE_MOZINFO'] = '1'
|
||||
# Until we have access to the virtualenv from this script, execute
|
||||
# config.status externally, with the virtualenv python.
|
||||
return subprocess.call([config['PYTHON'], 'config.status'])
|
||||
os.environ[b'WRITE_MOZINFO'] = b'1'
|
||||
from mozbuild.config_status import config_status
|
||||
return config_status(args=[], **encode(sanitized_config))
|
||||
return 0
|
||||
|
||||
|
||||
|
@ -8,9 +8,9 @@ const promise = require("promise");
|
||||
const {Task} = require("devtools/shared/task");
|
||||
const {KeyCodes} = require("devtools/client/shared/keycodes");
|
||||
|
||||
const system = require("devtools/shared/system");
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const {AutocompletePopup} = require("devtools/client/shared/autocomplete-popup");
|
||||
const Services = require("Services");
|
||||
|
||||
// Maximum number of selector suggestions shown in the panel.
|
||||
const MAX_SUGGESTIONS = 15;
|
||||
@ -130,7 +130,7 @@ InspectorSearch.prototype = {
|
||||
this._onSearch(event.shiftKey);
|
||||
}
|
||||
|
||||
const modifierKey = system.constants.platform === "macosx"
|
||||
const modifierKey = Services.appinfo.OS === "Darwin"
|
||||
? event.metaKey : event.ctrlKey;
|
||||
if (event.keyCode === KeyCodes.DOM_VK_G && modifierKey) {
|
||||
this._onSearch(event.shiftKey);
|
||||
|
@ -7369,7 +7369,7 @@ nsDocShell::OnStateChange(nsIWebProgress* aProgress, nsIRequest* aRequest,
|
||||
|
||||
if ((aStateFlags & STATE_RESTORING) == 0) {
|
||||
// Show the progress cursor if the pref is set
|
||||
if (Preferences::GetBool("ui.use_activity_cursor", false)) {
|
||||
if (nsContentUtils::UseActivityCursor()) {
|
||||
nsCOMPtr<nsIWidget> mainWidget;
|
||||
GetMainWidget(getter_AddRefs(mainWidget));
|
||||
if (mainWidget) {
|
||||
@ -7385,7 +7385,7 @@ nsDocShell::OnStateChange(nsIWebProgress* aProgress, nsIRequest* aRequest,
|
||||
mBusyFlags = BUSY_FLAGS_NONE;
|
||||
|
||||
// Hide the progress cursor if the pref is set
|
||||
if (Preferences::GetBool("ui.use_activity_cursor", false)) {
|
||||
if (nsContentUtils::UseActivityCursor()) {
|
||||
nsCOMPtr<nsIWidget> mainWidget;
|
||||
GetMainWidget(getter_AddRefs(mainWidget));
|
||||
if (mainWidget) {
|
||||
|
@ -1543,6 +1543,13 @@ GetCumulativeDistances(const nsTArray<ComputedKeyframeValues>& aValues,
|
||||
continue;
|
||||
}
|
||||
|
||||
// Sort the pacedValues first, so the order of subproperties of
|
||||
// pacedValues is always the same as that of prevPacedValues.
|
||||
if (isShorthand) {
|
||||
pacedValues.Sort(
|
||||
TPropertyPriorityComparator<PropertyStyleAnimationValuePair>());
|
||||
}
|
||||
|
||||
if (prevPacedValues.IsEmpty()) {
|
||||
// This is the first paceable keyframe so its cumulative distance is 0.0.
|
||||
cumulativeDistances[i] = 0.0;
|
||||
|
20
dom/animation/test/crashtests/1290535-1.html
Normal file
20
dom/animation/test/crashtests/1290535-1.html
Normal file
@ -0,0 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bug 1290535 - Sort paced subproperties of a shorthand property</title>
|
||||
<meta charset="UTF-8">
|
||||
<script>
|
||||
|
||||
function test()
|
||||
{
|
||||
var div = document.createElement('div');
|
||||
document.documentElement.appendChild(div);
|
||||
div.animate([ { borderRadius: "0", borderTopRightRadius: "0" },
|
||||
{ borderRadius: "50%" } ],
|
||||
{ spacing:"paced(border-radius)" });
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="test();"></body>
|
||||
</html>
|
@ -10,3 +10,4 @@ pref(dom.animations-api.core.enabled,true) load 1272475-1.html
|
||||
pref(dom.animations-api.core.enabled,true) load 1272475-2.html
|
||||
pref(dom.animations-api.core.enabled,true) load 1278485-1.html
|
||||
pref(dom.animations-api.core.enabled,true) load 1277272-1.html
|
||||
pref(dom.animations-api.core.enabled,true) load 1290535-1.html
|
||||
|
@ -41,6 +41,7 @@ support-files =
|
||||
mozilla/file_document-timeline-origin-time-range.html
|
||||
mozilla/file_hide_and_show.html
|
||||
mozilla/file_partial_keyframes.html
|
||||
mozilla/file_spacing_property_order.html
|
||||
mozilla/file_transform_limits.html
|
||||
mozilla/file_underlying-discrete-value.html
|
||||
style/file_animation-seeking-with-current-time.html
|
||||
@ -91,6 +92,7 @@ skip-if = (toolkit == 'gonk' && debug)
|
||||
[mozilla/test_hide_and_show.html]
|
||||
[mozilla/test_partial_keyframes.html]
|
||||
[mozilla/test_set-easing.html]
|
||||
[mozilla/test_spacing_property_order.html]
|
||||
[mozilla/test_transform_limits.html]
|
||||
[mozilla/test_underlying-discrete-value.html]
|
||||
[style/test_animation-seeking-with-current-time.html]
|
||||
|
33
dom/animation/test/mozilla/file_spacing_property_order.html
Normal file
33
dom/animation/test/mozilla/file_spacing_property_order.html
Normal file
@ -0,0 +1,33 @@
|
||||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<script src="../testcommon.js"></script>
|
||||
<body>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
test(function(t) {
|
||||
var div = document.createElement('div');
|
||||
document.documentElement.appendChild(div);
|
||||
var anim = div.animate([ { borderRadius: "0", borderTopRightRadius: "10%" },
|
||||
{ borderTopLeftRadius: "20%",
|
||||
borderTopRightRadius: "30%",
|
||||
borderBottomRightRadius: "40%",
|
||||
borderBottomLeftRadius: "50%" },
|
||||
{ borderRadius: "50%" } ],
|
||||
{ spacing:"paced(border-radius)" });
|
||||
|
||||
var frames = anim.effect.getKeyframes();
|
||||
var dist = [ 0,
|
||||
Math.sqrt(20 * 20 + (30 - 10) * (30 - 10) + 40 * 40 + 50 * 50),
|
||||
Math.sqrt((50 - 20) * (50 - 20) + (50 - 30) * (50 - 30) +
|
||||
(50 - 40) * (50 - 40) + (50 - 50) * (50 - 50)) ];
|
||||
var cumDist = [];
|
||||
dist.reduce(function(prev, curr, i) { return cumDist[i] = prev + curr; }, 0);
|
||||
assert_approx_equals(frames[1].computedOffset, cumDist[1] / cumDist[2],
|
||||
0.0001, 'frame offset');
|
||||
}, 'Test for the longhand components of the shorthand property surely sorted' );
|
||||
|
||||
done();
|
||||
|
||||
</script>
|
||||
</body>
|
14
dom/animation/test/mozilla/test_spacing_property_order.html
Normal file
14
dom/animation/test/mozilla/test_spacing_property_order.html
Normal file
@ -0,0 +1,14 @@
|
||||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
'use strict';
|
||||
setup({explicit_done: true});
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{ "set": [["dom.animations-api.core.enabled", true]]},
|
||||
function() {
|
||||
window.open("file_spacing_property_order.html");
|
||||
});
|
||||
</script>
|
@ -282,6 +282,7 @@ bool nsContentUtils::sGettersDecodeURLHash = false;
|
||||
bool nsContentUtils::sPrivacyResistFingerprinting = false;
|
||||
bool nsContentUtils::sSendPerformanceTimingNotifications = false;
|
||||
bool nsContentUtils::sAppendLFInSerialization = false;
|
||||
bool nsContentUtils::sUseActivityCursor = false;
|
||||
|
||||
uint32_t nsContentUtils::sHandlingInputTimeout = 1000;
|
||||
|
||||
@ -606,6 +607,9 @@ nsContentUtils::Init()
|
||||
Preferences::AddBoolVarCache(&sDoNotTrackEnabled,
|
||||
"privacy.donottrackheader.enabled", false);
|
||||
|
||||
Preferences::AddBoolVarCache(&sUseActivityCursor,
|
||||
"ui.use_activity_cursor", false);
|
||||
|
||||
Element::InitCCCallbacks();
|
||||
|
||||
nsCOMPtr<nsIUUIDGenerator> uuidGenerator =
|
||||
|
@ -2062,6 +2062,14 @@ public:
|
||||
return sPrivacyResistFingerprinting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the browser should show busy cursor when loading page.
|
||||
*/
|
||||
static bool UseActivityCursor()
|
||||
{
|
||||
return sUseActivityCursor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this doc is controlled by a ServiceWorker.
|
||||
*/
|
||||
@ -2781,6 +2789,7 @@ private:
|
||||
static bool sPrivacyResistFingerprinting;
|
||||
static bool sSendPerformanceTimingNotifications;
|
||||
static bool sAppendLFInSerialization;
|
||||
static bool sUseActivityCursor;
|
||||
static uint32_t sCookiesLifetimePolicy;
|
||||
static uint32_t sCookiesBehavior;
|
||||
|
||||
|
@ -3567,7 +3567,7 @@ EventStateManager::UpdateCursor(nsPresContext* aPresContext,
|
||||
hotspotY = framecursor.mHotspotY;
|
||||
}
|
||||
|
||||
if (Preferences::GetBool("ui.use_activity_cursor", false)) {
|
||||
if (nsContentUtils::UseActivityCursor()) {
|
||||
// Check whether or not to show the busy cursor
|
||||
nsCOMPtr<nsIDocShell> docShell(aPresContext->GetDocShell());
|
||||
if (!docShell) return;
|
||||
|
@ -19,6 +19,7 @@ interface nsIPushSubscription : nsISupports
|
||||
readonly attribute long long lastPush;
|
||||
readonly attribute long quota;
|
||||
readonly attribute bool isSystemSubscription;
|
||||
readonly attribute jsval p256dhPrivateKey;
|
||||
|
||||
bool quotaApplies();
|
||||
bool isExpired();
|
||||
|
@ -41,7 +41,8 @@ ADTSDecoder::IsEnabled()
|
||||
ADTSDecoder::CanHandleMediaType(const nsACString& aType,
|
||||
const nsAString& aCodecs)
|
||||
{
|
||||
if (aType.EqualsASCII("audio/aac") || aType.EqualsASCII("audio/aacp")) {
|
||||
if (aType.EqualsASCII("audio/aac") || aType.EqualsASCII("audio/aacp") ||
|
||||
aType.EqualsASCII("audio/x-aac")) {
|
||||
return IsEnabled() && (aCodecs.IsEmpty() || aCodecs.EqualsASCII("aac"));
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ public:
|
||||
MediaDecoder* Clone(MediaDecoderOwner* aOwner) override;
|
||||
MediaDecoderStateMachine* CreateStateMachine() override;
|
||||
|
||||
// Returns true if the MP3 backend is pref'ed on, and we're running on a
|
||||
// Returns true if the ADTS backend is pref'ed on, and we're running on a
|
||||
// platform that is likely to have decoders for the format.
|
||||
static bool IsEnabled();
|
||||
static bool CanHandleMediaType(const nsACString& aType,
|
||||
|
@ -80,6 +80,11 @@ AudioSampleToFloat(int16_t aValue)
|
||||
{
|
||||
return aValue/32768.0f;
|
||||
}
|
||||
inline float
|
||||
AudioSampleToFloat(int32_t aValue)
|
||||
{
|
||||
return aValue/(float)(1U<<31);
|
||||
}
|
||||
|
||||
template <typename T> T FloatToAudioSample(float aValue);
|
||||
|
||||
|
@ -53,7 +53,11 @@
|
||||
#include "ADTSDecoder.h"
|
||||
#include "ADTSDemuxer.h"
|
||||
|
||||
#include "FlacDecoder.h"
|
||||
#include "FlacDemuxer.h"
|
||||
|
||||
#include "nsPluginHost.h"
|
||||
#include "MediaPrefs.h"
|
||||
|
||||
namespace mozilla
|
||||
{
|
||||
@ -91,36 +95,17 @@ IsRawType(const nsACString& aType)
|
||||
}
|
||||
#endif
|
||||
|
||||
// See http://www.rfc-editor.org/rfc/rfc5334.txt for the definitions
|
||||
// of Ogg media types and codec types
|
||||
static const char* const gOggTypes[4] = {
|
||||
"video/ogg",
|
||||
"audio/ogg",
|
||||
"application/ogg",
|
||||
nullptr
|
||||
};
|
||||
|
||||
static char const *const gOggCodecs[3] = {
|
||||
"vorbis",
|
||||
"theora",
|
||||
nullptr
|
||||
};
|
||||
|
||||
static char const *const gOggCodecsWithOpus[4] = {
|
||||
"vorbis",
|
||||
"opus",
|
||||
"theora",
|
||||
nullptr
|
||||
};
|
||||
static bool
|
||||
IsOggSupportedType(const nsACString& aType,
|
||||
const nsAString& aCodecs = EmptyString())
|
||||
{
|
||||
return OggDecoder::CanHandleMediaType(aType, aCodecs);
|
||||
}
|
||||
|
||||
static bool
|
||||
IsOggType(const nsACString& aType)
|
||||
IsOggTypeAndEnabled(const nsACString& aType)
|
||||
{
|
||||
if (!MediaDecoder::IsOggEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return CodecListContains(gOggTypes, aType);
|
||||
return IsOggSupportedType(aType);
|
||||
}
|
||||
|
||||
// See http://www.rfc-editor.org/rfc/rfc2361.txt for the definitions
|
||||
@ -338,6 +323,13 @@ IsWAVSupportedType(const nsACString& aType,
|
||||
return WaveDecoder::CanHandleMediaType(aType, aCodecs);
|
||||
}
|
||||
|
||||
static bool
|
||||
IsFlacSupportedType(const nsACString& aType,
|
||||
const nsAString& aCodecs = EmptyString())
|
||||
{
|
||||
return FlacDecoder::CanHandleMediaType(aType, aCodecs);
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool DecoderTraits::ShouldHandleMediaType(const char* aMIMEType,
|
||||
DecoderDoctorDiagnostics* aDiagnostics)
|
||||
@ -378,8 +370,14 @@ DecoderTraits::CanHandleCodecsType(const char* aMIMEType,
|
||||
codecList = gRawCodecs;
|
||||
}
|
||||
#endif
|
||||
if (IsOggType(nsDependentCString(aMIMEType))) {
|
||||
codecList = MediaDecoder::IsOpusEnabled() ? gOggCodecsWithOpus : gOggCodecs;
|
||||
if (IsOggTypeAndEnabled(nsDependentCString(aMIMEType))) {
|
||||
if (IsOggSupportedType(nsDependentCString(aMIMEType), aRequestedCodecs)) {
|
||||
return CANPLAY_YES;
|
||||
} else {
|
||||
// We can only reach this position if a particular codec was requested,
|
||||
// ogg is supported and working: the codec must be invalid.
|
||||
return CANPLAY_NO;
|
||||
}
|
||||
}
|
||||
if (IsWaveType(nsDependentCString(aMIMEType))) {
|
||||
codecList = gWaveCodecs;
|
||||
@ -412,6 +410,9 @@ DecoderTraits::CanHandleCodecsType(const char* aMIMEType,
|
||||
if (IsAACSupportedType(nsDependentCString(aMIMEType), aRequestedCodecs)) {
|
||||
return CANPLAY_YES;
|
||||
}
|
||||
if (IsFlacSupportedType(nsDependentCString(aMIMEType), aRequestedCodecs)) {
|
||||
return CANPLAY_YES;
|
||||
}
|
||||
#ifdef MOZ_OMX_DECODER
|
||||
if (IsOmxSupportedType(nsDependentCString(aMIMEType))) {
|
||||
if (nsDependentCString(aMIMEType).EqualsASCII("audio/mpeg")) {
|
||||
@ -485,7 +486,7 @@ DecoderTraits::CanHandleMediaType(const char* aMIMEType,
|
||||
return CANPLAY_MAYBE;
|
||||
}
|
||||
#endif
|
||||
if (IsOggType(nsDependentCString(aMIMEType))) {
|
||||
if (IsOggTypeAndEnabled(nsDependentCString(aMIMEType))) {
|
||||
return CANPLAY_MAYBE;
|
||||
}
|
||||
if (IsWaveType(nsDependentCString(aMIMEType))) {
|
||||
@ -505,6 +506,9 @@ DecoderTraits::CanHandleMediaType(const char* aMIMEType,
|
||||
if (IsAACSupportedType(nsDependentCString(aMIMEType))) {
|
||||
return CANPLAY_MAYBE;
|
||||
}
|
||||
if (IsFlacSupportedType(nsDependentCString(aMIMEType))) {
|
||||
return CANPLAY_MAYBE;
|
||||
}
|
||||
#ifdef MOZ_OMX_DECODER
|
||||
if (IsOmxSupportedType(nsDependentCString(aMIMEType))) {
|
||||
return CANPLAY_MAYBE;
|
||||
@ -554,7 +558,7 @@ InstantiateDecoder(const nsACString& aType,
|
||||
return decoder.forget();
|
||||
}
|
||||
#endif
|
||||
if (IsOggType(aType)) {
|
||||
if (IsOggSupportedType(aType)) {
|
||||
decoder = new OggDecoder(aOwner);
|
||||
return decoder.forget();
|
||||
}
|
||||
@ -562,6 +566,10 @@ InstantiateDecoder(const nsACString& aType,
|
||||
decoder = new WaveDecoder(aOwner);
|
||||
return decoder.forget();
|
||||
}
|
||||
if (IsFlacSupportedType(aType)) {
|
||||
decoder = new FlacDecoder(aOwner);
|
||||
return decoder.forget();
|
||||
}
|
||||
#ifdef MOZ_OMX_DECODER
|
||||
if (IsOmxSupportedType(aType)) {
|
||||
// we are discouraging Web and App developers from using those formats in
|
||||
@ -646,13 +654,16 @@ MediaDecoderReader* DecoderTraits::CreateReader(const nsACString& aType, Abstrac
|
||||
if (IsWAVSupportedType(aType)) {
|
||||
decoderReader = new MediaFormatReader(aDecoder, new WAVDemuxer(aDecoder->GetResource()));
|
||||
} else
|
||||
if (IsFlacSupportedType(aType)) {
|
||||
decoderReader = new MediaFormatReader(aDecoder, new FlacDemuxer(aDecoder->GetResource()));
|
||||
} else
|
||||
#ifdef MOZ_RAW
|
||||
if (IsRawType(aType)) {
|
||||
decoderReader = new RawReader(aDecoder);
|
||||
} else
|
||||
#endif
|
||||
if (IsOggType(aType)) {
|
||||
decoderReader = Preferences::GetBool("media.format-reader.ogg", true) ?
|
||||
if (IsOggSupportedType(aType)) {
|
||||
decoderReader = MediaPrefs::OggFormatReader() ?
|
||||
static_cast<MediaDecoderReader*>(new MediaFormatReader(aDecoder, new OggDemuxer(aDecoder->GetResource()))) :
|
||||
new OggReader(aDecoder);
|
||||
} else
|
||||
@ -696,7 +707,7 @@ bool DecoderTraits::IsSupportedInVideoDocument(const nsACString& aType)
|
||||
}
|
||||
|
||||
return
|
||||
IsOggType(aType) ||
|
||||
IsOggSupportedType(aType) ||
|
||||
#ifdef MOZ_OMX_DECODER
|
||||
// We support the formats in gB2GOnlyTypes only inside WebApps on firefoxOS
|
||||
// but not in general web content. Ensure we dont create a VideoDocument
|
||||
@ -713,6 +724,7 @@ bool DecoderTraits::IsSupportedInVideoDocument(const nsACString& aType)
|
||||
#endif
|
||||
IsMP3SupportedType(aType) ||
|
||||
IsAACSupportedType(aType) ||
|
||||
IsFlacSupportedType(aType) ||
|
||||
#ifdef MOZ_DIRECTSHOW
|
||||
IsDirectShowSupportedType(aType) ||
|
||||
#endif
|
||||
|
@ -862,12 +862,25 @@ MediaDevice::GetId(nsAString& aID)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MediaDevice::GetRawId(nsAString& aID)
|
||||
{
|
||||
aID.Assign(mRawID);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
MediaDevice::SetId(const nsAString& aID)
|
||||
{
|
||||
mID.Assign(aID);
|
||||
}
|
||||
|
||||
void
|
||||
MediaDevice::SetRawId(const nsAString& aID)
|
||||
{
|
||||
mRawID.Assign(aID);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MediaDevice::GetMediaSource(nsAString& aMediaSource)
|
||||
{
|
||||
@ -2465,6 +2478,7 @@ MediaManager::AnonymizeDevices(SourceSet& aDevices, const nsACString& aOriginKey
|
||||
for (auto& device : aDevices) {
|
||||
nsString id;
|
||||
device->GetId(id);
|
||||
device->SetRawId(id);
|
||||
AnonymizeId(id, aOriginKey);
|
||||
device->SetId(id);
|
||||
}
|
||||
|
@ -70,6 +70,7 @@ public:
|
||||
NS_DECL_NSIMEDIADEVICE
|
||||
|
||||
void SetId(const nsAString& aID);
|
||||
void SetRawId(const nsAString& aID);
|
||||
virtual uint32_t GetBestFitnessDistance(
|
||||
const nsTArray<const NormalizedConstraintSet*>& aConstraintSets);
|
||||
virtual Source* GetSource() = 0;
|
||||
@ -95,6 +96,7 @@ private:
|
||||
protected:
|
||||
nsString mName;
|
||||
nsString mID;
|
||||
nsString mRawID;
|
||||
dom::MediaSourceEnum mMediaSource;
|
||||
RefPtr<MediaEngineSource> mSource;
|
||||
RefPtr<MediaEngineSource::AllocationHandle> mAllocationHandle;
|
||||
|
@ -92,6 +92,9 @@ private:
|
||||
DECL_MEDIA_PREF("media.resampling.rate", AudioSinkResampleRate, uint32_t, 48000);
|
||||
DECL_MEDIA_PREF("media.forcestereo.enabled", AudioSinkForceStereo, bool, true);
|
||||
|
||||
// VideoSink
|
||||
DECL_MEDIA_PREF("media.ruin-av-sync.enabled", RuinAvSync, bool, false);
|
||||
|
||||
// PlatformDecoderModule
|
||||
DECL_MEDIA_PREF("media.apple.forcevda", AppleForceVDA, bool, false);
|
||||
DECL_MEDIA_PREF("media.gmp.insecure.allow", GMPAllowInsecure, bool, false);
|
||||
@ -144,6 +147,13 @@ private:
|
||||
DECL_MEDIA_PREF("media.num-decode-threads", MediaThreadPoolDefaultCount, uint32_t, 4);
|
||||
DECL_MEDIA_PREF("media.decoder.limit", MediaDecoderLimit, int32_t, MediaDecoderLimitDefault());
|
||||
|
||||
// Ogg
|
||||
DECL_MEDIA_PREF("media.ogg.enabled", OggEnabled, bool, true);
|
||||
DECL_MEDIA_PREF("media.format-reader.ogg", OggFormatReader, bool, true);
|
||||
// Flac
|
||||
DECL_MEDIA_PREF("media.ogg.flac.enabled", FlacInOgg, bool, false);
|
||||
DECL_MEDIA_PREF("media.flac.enabled", FlacEnabled, bool, true);
|
||||
|
||||
public:
|
||||
// Manage the singleton:
|
||||
static MediaPrefs& GetSingleton();
|
||||
|
52
dom/media/flac/FlacDecoder.cpp
Normal file
52
dom/media/flac/FlacDecoder.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "FlacDecoder.h"
|
||||
#include "FlacDemuxer.h"
|
||||
#include "MediaDecoderStateMachine.h"
|
||||
#include "MediaFormatReader.h"
|
||||
#include "MediaPrefs.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
MediaDecoder*
|
||||
FlacDecoder::Clone(MediaDecoderOwner* aOwner)
|
||||
{
|
||||
if (!IsEnabled())
|
||||
return nullptr;
|
||||
|
||||
return new FlacDecoder(aOwner);
|
||||
}
|
||||
|
||||
MediaDecoderStateMachine*
|
||||
FlacDecoder::CreateStateMachine()
|
||||
{
|
||||
RefPtr<MediaDecoderReader> reader =
|
||||
new MediaFormatReader(this, new FlacDemuxer(GetResource()));
|
||||
return new MediaDecoderStateMachine(this, reader);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
FlacDecoder::IsEnabled()
|
||||
{
|
||||
#ifdef MOZ_FFVPX
|
||||
return MediaPrefs::FlacEnabled();
|
||||
#else
|
||||
// Until bug 1295886 is fixed.
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
FlacDecoder::CanHandleMediaType(const nsACString& aType,
|
||||
const nsAString& aCodecs)
|
||||
{
|
||||
return IsEnabled() &&
|
||||
(aType.EqualsASCII("audio/flac") || aType.EqualsASCII("audio/x-flac") ||
|
||||
aType.EqualsASCII("application/x-flac"));
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
30
dom/media/flac/FlacDecoder.h
Normal file
30
dom/media/flac/FlacDecoder.h
Normal file
@ -0,0 +1,30 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 FLAC_DECODER_H_
|
||||
#define FLAC_DECODER_H_
|
||||
|
||||
#include "MediaDecoder.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class FlacDecoder : public MediaDecoder {
|
||||
public:
|
||||
// MediaDecoder interface.
|
||||
explicit FlacDecoder(MediaDecoderOwner* aOwner) : MediaDecoder(aOwner) {}
|
||||
MediaDecoder* Clone(MediaDecoderOwner* aOwner) override;
|
||||
MediaDecoderStateMachine* CreateStateMachine() override;
|
||||
|
||||
// Returns true if the Flac backend is pref'ed on, and we're running on a
|
||||
// platform that is likely to have decoders for the format.
|
||||
static bool IsEnabled();
|
||||
static bool CanHandleMediaType(const nsACString& aType,
|
||||
const nsAString& aCodecs);
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // !FLAC_DECODER_H_
|
1074
dom/media/flac/FlacDemuxer.cpp
Normal file
1074
dom/media/flac/FlacDemuxer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
108
dom/media/flac/FlacDemuxer.h
Normal file
108
dom/media/flac/FlacDemuxer.h
Normal file
@ -0,0 +1,108 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 FLAC_DEMUXER_H_
|
||||
#define FLAC_DEMUXER_H_
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "MediaDataDemuxer.h"
|
||||
#include "MediaResource.h"
|
||||
namespace mozilla {
|
||||
|
||||
namespace flac {
|
||||
class Frame;
|
||||
class FrameParser;
|
||||
}
|
||||
class FlacTrackDemuxer;
|
||||
|
||||
|
||||
class FlacDemuxer : public MediaDataDemuxer {
|
||||
public:
|
||||
// MediaDataDemuxer interface.
|
||||
explicit FlacDemuxer(MediaResource* aSource);
|
||||
RefPtr<InitPromise> Init() override;
|
||||
bool HasTrackType(TrackInfo::TrackType aType) const override;
|
||||
uint32_t GetNumberTracks(TrackInfo::TrackType aType) const override;
|
||||
already_AddRefed<MediaTrackDemuxer> GetTrackDemuxer(
|
||||
TrackInfo::TrackType aType, uint32_t aTrackNumber) override;
|
||||
bool IsSeekable() const override;
|
||||
|
||||
// Return true if a valid flac frame header could be found.
|
||||
static bool FlacSniffer(const uint8_t* aData, const uint32_t aLength);
|
||||
|
||||
private:
|
||||
bool InitInternal();
|
||||
|
||||
RefPtr<MediaResource> mSource;
|
||||
RefPtr<FlacTrackDemuxer> mTrackDemuxer;
|
||||
};
|
||||
|
||||
class FlacTrackDemuxer : public MediaTrackDemuxer {
|
||||
public:
|
||||
explicit FlacTrackDemuxer(MediaResource* aSource);
|
||||
|
||||
// Initializes the track demuxer by reading the first frame for meta data.
|
||||
// Returns initialization success state.
|
||||
bool Init();
|
||||
|
||||
// MediaTrackDemuxer interface.
|
||||
UniquePtr<TrackInfo> GetInfo() const override;
|
||||
RefPtr<SeekPromise> Seek(media::TimeUnit aTime) override;
|
||||
RefPtr<SamplesPromise> GetSamples(int32_t aNumSamples = 1) override;
|
||||
void Reset() override;
|
||||
int64_t GetResourceOffset() const override;
|
||||
media::TimeIntervals GetBuffered() override;
|
||||
RefPtr<SkipAccessPointPromise> SkipToNextRandomAccessPoint(
|
||||
media::TimeUnit aTimeThreshold) override;
|
||||
|
||||
bool IsSeekable() const;
|
||||
|
||||
private:
|
||||
// Destructor.
|
||||
~FlacTrackDemuxer();
|
||||
|
||||
// Returns the estimated stream duration, or a 0-duration if unknown.
|
||||
media::TimeUnit Duration() const;
|
||||
media::TimeUnit TimeAtEnd();
|
||||
|
||||
// Fast approximate seeking to given time.
|
||||
media::TimeUnit FastSeek(const media::TimeUnit& aTime);
|
||||
|
||||
// Seeks by scanning the stream up to the given time for more accurate results.
|
||||
media::TimeUnit ScanUntil(const media::TimeUnit& aTime);
|
||||
|
||||
// Finds the next valid frame and return it.
|
||||
const flac::Frame& FindNextFrame();
|
||||
|
||||
// Returns the next ADTS frame, if available.
|
||||
already_AddRefed<MediaRawData> GetNextFrame(const flac::Frame& aFrame);
|
||||
|
||||
// Reads aSize bytes into aBuffer from the source starting at aOffset.
|
||||
// Returns the actual size read.
|
||||
int32_t Read(uint8_t* aBuffer, int64_t aOffset, int32_t aSize);
|
||||
|
||||
// Returns the average frame length derived from the previously parsed frames.
|
||||
double AverageFrameLength() const;
|
||||
|
||||
// The (hopefully) Flac resource.
|
||||
MediaResourceIndex mSource;
|
||||
|
||||
// Flac frame parser used to detect frames and extract side info.
|
||||
nsAutoPtr<flac::FrameParser> mParser;
|
||||
|
||||
// Total duration of parsed frames.
|
||||
media::TimeUnit mParsedFramesDuration;
|
||||
|
||||
// Sum of parsed frames' lengths in bytes.
|
||||
uint64_t mTotalFrameLen;
|
||||
|
||||
// Audio track config info.
|
||||
UniquePtr<AudioInfo> mInfo;
|
||||
};
|
||||
|
||||
} // mozilla
|
||||
|
||||
#endif // !FLAC_DEMUXER_H_
|
258
dom/media/flac/FlacFrameParser.cpp
Normal file
258
dom/media/flac/FlacFrameParser.cpp
Normal file
@ -0,0 +1,258 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "FlacFrameParser.h"
|
||||
#include "mp4_demuxer/ByteReader.h"
|
||||
#include "nsTArray.h"
|
||||
#include "OggCodecState.h"
|
||||
#include "VideoUtils.h"
|
||||
|
||||
namespace mozilla
|
||||
{
|
||||
|
||||
class AutoByteReader : public mp4_demuxer::ByteReader
|
||||
{
|
||||
public:
|
||||
AutoByteReader(const uint8_t* aData, size_t aSize)
|
||||
: mp4_demuxer::ByteReader(aData, aSize)
|
||||
{
|
||||
|
||||
}
|
||||
virtual ~AutoByteReader()
|
||||
{
|
||||
DiscardRemaining();
|
||||
}
|
||||
};
|
||||
|
||||
#define OGG_FLAC_METADATA_TYPE_STREAMINFO 0x7F
|
||||
#define FLAC_STREAMINFO_SIZE 34
|
||||
|
||||
#define BITMASK(x) ((1ULL << x)-1)
|
||||
|
||||
enum
|
||||
{
|
||||
FLAC_METADATA_TYPE_STREAMINFO = 0,
|
||||
FLAC_METADATA_TYPE_PADDING,
|
||||
FLAC_METADATA_TYPE_APPLICATION,
|
||||
FLAC_METADATA_TYPE_SEEKTABLE,
|
||||
FLAC_METADATA_TYPE_VORBIS_COMMENT,
|
||||
FLAC_METADATA_TYPE_CUESHEET,
|
||||
FLAC_METADATA_TYPE_PICTURE,
|
||||
FLAC_METADATA_TYPE_INVALID = 127
|
||||
};
|
||||
|
||||
FlacFrameParser::FlacFrameParser()
|
||||
: mMinBlockSize(0)
|
||||
, mMaxBlockSize(0)
|
||||
, mMinFrameSize(0)
|
||||
, mMaxFrameSize(0)
|
||||
, mNumFrames(0)
|
||||
, mFullMetadata(false)
|
||||
, mPacketCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
uint32_t
|
||||
FlacFrameParser::HeaderBlockLength(const uint8_t* aPacket) const
|
||||
{
|
||||
uint32_t extra = 4;
|
||||
if (aPacket[0] == 'f') {
|
||||
// This must be the first block read, which contains the fLaC signature.
|
||||
aPacket += 4;
|
||||
extra += 4;
|
||||
}
|
||||
return (BigEndian::readUint32(aPacket) & BITMASK(24)) + extra;
|
||||
}
|
||||
|
||||
bool
|
||||
FlacFrameParser::DecodeHeaderBlock(const uint8_t* aPacket, size_t aLength)
|
||||
{
|
||||
if (aLength < 4 || aPacket[0] == 0xff) {
|
||||
// Not a header block.
|
||||
return false;
|
||||
}
|
||||
AutoByteReader br(aPacket, aLength);
|
||||
|
||||
mPacketCount++;
|
||||
|
||||
if (aPacket[0] == 'f') {
|
||||
if (mPacketCount != 1 || memcmp(br.Read(4), "fLaC", 4) ||
|
||||
br.Remaining() != FLAC_STREAMINFO_SIZE + 4) {
|
||||
return false;
|
||||
}
|
||||
aPacket += 4;
|
||||
aLength -= 4;
|
||||
}
|
||||
uint8_t blockHeader = br.ReadU8();
|
||||
// blockType is a misnomer as it could indicate here either a packet type
|
||||
// should it points to the start of a Flac in Ogg metadata, or an actual
|
||||
// block type as per the flac specification.
|
||||
uint32_t blockType = blockHeader & 0x7f;
|
||||
bool lastBlock = blockHeader & 0x80;
|
||||
|
||||
if (blockType == OGG_FLAC_METADATA_TYPE_STREAMINFO) {
|
||||
if (mPacketCount != 1 || memcmp(br.Read(4), "FLAC", 4) ||
|
||||
br.Remaining() != FLAC_STREAMINFO_SIZE + 12) {
|
||||
return false;
|
||||
}
|
||||
uint32_t major = br.ReadU8();
|
||||
if (major != 1) {
|
||||
// unsupported version;
|
||||
return false;
|
||||
}
|
||||
br.ReadU8(); // minor version
|
||||
mNumHeaders = Some(uint32_t(br.ReadU16()));
|
||||
br.Read(4); // fLaC
|
||||
blockType = br.ReadU8() & BITMASK(7);
|
||||
// First METADATA_BLOCK_STREAMINFO
|
||||
if (blockType != FLAC_METADATA_TYPE_STREAMINFO) {
|
||||
// First block must be a stream info.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t blockDataSize = br.ReadU24();
|
||||
const uint8_t* blockDataStart = br.Peek(blockDataSize);
|
||||
if (!blockDataStart) {
|
||||
// Incomplete block.
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (blockType) {
|
||||
case FLAC_METADATA_TYPE_STREAMINFO:
|
||||
{
|
||||
if (mPacketCount != 1 || blockDataSize != FLAC_STREAMINFO_SIZE) {
|
||||
// STREAMINFO must be the first metadata block found, and its size
|
||||
// is constant.
|
||||
return false;
|
||||
}
|
||||
|
||||
mMinBlockSize = br.ReadU16();
|
||||
mMaxBlockSize = br.ReadU16();
|
||||
mMinFrameSize = br.ReadU24();
|
||||
mMaxFrameSize = br.ReadU24();
|
||||
|
||||
uint64_t blob = br.ReadU64();
|
||||
uint32_t sampleRate = (blob >> 44) & BITMASK(20);
|
||||
if (!sampleRate) {
|
||||
return false;
|
||||
}
|
||||
uint32_t numChannels = ((blob >> 41) & BITMASK(3)) + 1;
|
||||
if (numChannels > FLAC_MAX_CHANNELS) {
|
||||
return false;
|
||||
}
|
||||
uint32_t bps = ((blob >> 38) & BITMASK(5)) + 1;
|
||||
if (bps > 24) {
|
||||
return false;
|
||||
}
|
||||
mNumFrames = blob & BITMASK(36);
|
||||
|
||||
mInfo.mMimeType = "audio/flac";
|
||||
mInfo.mRate = sampleRate;
|
||||
mInfo.mChannels = numChannels;
|
||||
mInfo.mBitDepth = bps;
|
||||
mInfo.mCodecSpecificConfig->AppendElements(blockDataStart, blockDataSize);
|
||||
CheckedInt64 duration =
|
||||
SaferMultDiv(mNumFrames, USECS_PER_S, sampleRate);
|
||||
mInfo.mDuration = duration.isValid() ? duration.value() : 0;
|
||||
mParser = new OpusParser;
|
||||
break;
|
||||
}
|
||||
case FLAC_METADATA_TYPE_VORBIS_COMMENT:
|
||||
{
|
||||
if (!mParser) {
|
||||
// We must have seen a valid streaminfo first.
|
||||
return false;
|
||||
}
|
||||
nsTArray<uint8_t> comments(blockDataSize + 8);
|
||||
comments.AppendElements("OpusTags", 8);
|
||||
comments.AppendElements(blockDataStart, blockDataSize);
|
||||
if (!mParser->DecodeTags(comments.Elements(), comments.Length())) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (mNumHeaders && mPacketCount > mNumHeaders.ref() + 1) {
|
||||
// Received too many header block. assuming invalid.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lastBlock || (mNumHeaders && mNumHeaders.ref() + 1 == mPacketCount)) {
|
||||
mFullMetadata = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int64_t
|
||||
FlacFrameParser::BlockDuration(const uint8_t* aPacket, size_t aLength) const
|
||||
{
|
||||
if (!mInfo.IsValid()) {
|
||||
return -1;
|
||||
}
|
||||
if (mMinBlockSize == mMaxBlockSize) {
|
||||
// block size is fixed, use this instead of looking at the frame header.
|
||||
return mMinBlockSize;
|
||||
}
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
FlacFrameParser::IsHeaderBlock(const uint8_t* aPacket, size_t aLength) const
|
||||
{
|
||||
// Ogg Flac header
|
||||
// The one-byte packet type 0x7F
|
||||
// The four-byte ASCII signature "FLAC", i.e. 0x46, 0x4C, 0x41, 0x43
|
||||
|
||||
// Flac header:
|
||||
// "fLaC", the FLAC stream marker in ASCII, meaning byte 0 of the stream is 0x66, followed by 0x4C 0x61 0x43
|
||||
|
||||
// If we detect either a ogg or plain flac header, then it must be valid.
|
||||
if (aLength < 4 || aPacket[0] == 0xff) {
|
||||
// A header is at least 4 bytes.
|
||||
return false;
|
||||
}
|
||||
if (aPacket[0] == 0x7f) {
|
||||
// Ogg packet
|
||||
AutoByteReader br(aPacket + 1, aLength - 1);
|
||||
const uint8_t* signature = br.Read(4);
|
||||
return signature && !memcmp(signature, "FLAC", 4);
|
||||
}
|
||||
AutoByteReader br(aPacket, aLength - 1);
|
||||
const uint8_t* signature = br.Read(4);
|
||||
if (signature && !memcmp(signature, "fLaC", 4)) {
|
||||
// Flac start header, must have STREAMINFO as first metadata block;
|
||||
if (!br.CanRead8()) {
|
||||
return false;
|
||||
}
|
||||
uint32_t blockType = br.ReadU8() & 0x7f;
|
||||
return blockType == FLAC_METADATA_TYPE_STREAMINFO;
|
||||
}
|
||||
char type = aPacket[0] & 0x7f;
|
||||
return type >= 1 && type <= 6;
|
||||
}
|
||||
|
||||
MetadataTags*
|
||||
FlacFrameParser::GetTags() const
|
||||
{
|
||||
MetadataTags* tags;
|
||||
|
||||
tags = new MetadataTags;
|
||||
for (uint32_t i = 0; i < mParser->mTags.Length(); i++) {
|
||||
OggCodecState::AddVorbisComment(tags,
|
||||
mParser->mTags[i].Data(),
|
||||
mParser->mTags[i].Length());
|
||||
}
|
||||
|
||||
return tags;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
64
dom/media/flac/FlacFrameParser.h
Normal file
64
dom/media/flac/FlacFrameParser.h
Normal file
@ -0,0 +1,64 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 FLAC_FRAME_PARSER_H_
|
||||
#define FLAC_FRAME_PARSER_H_
|
||||
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "MediaDecoder.h" // For MetadataTags
|
||||
#include "MediaInfo.h"
|
||||
#include "MediaResource.h"
|
||||
|
||||
namespace mozilla
|
||||
{
|
||||
|
||||
class OpusParser;
|
||||
|
||||
// Decode a Flac Metadata block contained in either a ogg packet
|
||||
// (https://xiph.org/flac/ogg_mapping.html) or in flac container
|
||||
// (https://xiph.org/flac/format.html#frame_header)
|
||||
|
||||
class FlacFrameParser
|
||||
{
|
||||
public:
|
||||
FlacFrameParser();
|
||||
|
||||
bool IsHeaderBlock(const uint8_t* aPacket, size_t aLength) const;
|
||||
// Return the length of the block header (METADATA_BLOCK_HEADER+
|
||||
// METADATA_BLOCK_DATA), aPacket must point to at least 4
|
||||
// bytes and to a valid block header start (as determined by IsHeaderBlock).
|
||||
uint32_t HeaderBlockLength(const uint8_t* aPacket) const;
|
||||
bool DecodeHeaderBlock(const uint8_t* aPacket, size_t aLength);
|
||||
bool HasFullMetadata() const { return mFullMetadata; }
|
||||
// Return the duration in frames found in the block. -1 if error
|
||||
// such as invalid packet.
|
||||
int64_t BlockDuration(const uint8_t* aPacket, size_t aLength) const;
|
||||
|
||||
// Return a hash table with tag metadata.
|
||||
MetadataTags* GetTags() const;
|
||||
|
||||
AudioInfo mInfo;
|
||||
|
||||
private:
|
||||
bool ReconstructFlacGranulepos(void);
|
||||
Maybe<uint32_t> mNumHeaders;
|
||||
uint32_t mMinBlockSize;
|
||||
uint32_t mMaxBlockSize;
|
||||
uint32_t mMinFrameSize;
|
||||
uint32_t mMaxFrameSize;
|
||||
uint64_t mNumFrames;
|
||||
bool mFullMetadata;
|
||||
uint32_t mPacketCount;
|
||||
|
||||
// Used to decode the vorbis comment metadata.
|
||||
nsAutoPtr<OpusParser> mParser;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // FLAC_FRAME_PARSER_H_
|
24
dom/media/flac/moz.build
Normal file
24
dom/media/flac/moz.build
Normal file
@ -0,0 +1,24 @@
|
||||
# -*- Mode: python; 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 += [
|
||||
'FlacDecoder.h',
|
||||
'FlacDemuxer.h',
|
||||
'FlacFrameParser.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'FlacDecoder.cpp',
|
||||
'FlacDemuxer.cpp',
|
||||
'FlacFrameParser.cpp',
|
||||
]
|
||||
|
||||
CXXFLAGS += CONFIG['MOZ_LIBVPX_CFLAGS']
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
if CONFIG['GNU_CXX']:
|
||||
CXXFLAGS += ['-Wno-error=shadow']
|
@ -236,12 +236,22 @@ MP4TrackDemuxer::MP4TrackDemuxer(MP4Demuxer* aParent,
|
||||
{
|
||||
EnsureUpToDateIndex(); // Force update of index
|
||||
|
||||
VideoInfo* videoInfo = mInfo->GetAsVideoInfo();
|
||||
// Collect telemetry from h264 AVCC SPS.
|
||||
if (mInfo->GetAsVideoInfo() &&
|
||||
if (videoInfo &&
|
||||
(mInfo->mMimeType.EqualsLiteral("video/mp4") ||
|
||||
mInfo->mMimeType.EqualsLiteral("video/avc"))) {
|
||||
mNeedSPSForTelemetry =
|
||||
AccumulateSPSTelemetry(mInfo->GetAsVideoInfo()->mExtraData);
|
||||
RefPtr<MediaByteBuffer> extraData = videoInfo->mExtraData;
|
||||
mNeedSPSForTelemetry = AccumulateSPSTelemetry(extraData);
|
||||
mp4_demuxer::SPSData spsdata;
|
||||
if (mp4_demuxer::H264::DecodeSPSFromExtraData(extraData, spsdata) &&
|
||||
spsdata.pic_width > 0 && spsdata.pic_height > 0 &&
|
||||
mp4_demuxer::H264::EnsureSPSIsSane(spsdata)) {
|
||||
videoInfo->mImage.width = spsdata.pic_width;
|
||||
videoInfo->mImage.height = spsdata.pic_height;
|
||||
videoInfo->mDisplay.width = spsdata.display_width;
|
||||
videoInfo->mDisplay.height = spsdata.display_height;
|
||||
}
|
||||
} else {
|
||||
// No SPS to be found.
|
||||
mNeedSPSForTelemetry = false;
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include "MediaQueue.h"
|
||||
#include "VideoSink.h"
|
||||
#include "MediaPrefs.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -37,6 +38,7 @@ VideoSink::VideoSink(AbstractThread* aThread,
|
||||
, mHasVideo(false)
|
||||
, mUpdateScheduler(aThread)
|
||||
, mVideoQueueSendToCompositorSize(aVQueueSentToCompositerSize)
|
||||
, mMinVideoQueueSize(MediaPrefs::RuinAvSync() ? 1 : 0)
|
||||
{
|
||||
MOZ_ASSERT(mAudioSink, "AudioSink should exist.");
|
||||
}
|
||||
@ -394,7 +396,7 @@ VideoSink::UpdateRenderedVideoFrames()
|
||||
|
||||
// Skip frames up to the playback position.
|
||||
int64_t lastDisplayedFrameEndTime = 0;
|
||||
while (VideoQueue().GetSize() > 0 &&
|
||||
while (VideoQueue().GetSize() > mMinVideoQueueSize &&
|
||||
clockTime > VideoQueue().PeekFront()->GetEndTime()) {
|
||||
RefPtr<MediaData> frame = VideoQueue().PopFront();
|
||||
if (frame->As<VideoData>()->mSentToCompositor) {
|
||||
|
@ -139,6 +139,15 @@ private:
|
||||
// Max frame number sent to compositor at a time.
|
||||
// Based on the pref value obtained in MDSM.
|
||||
const uint32_t mVideoQueueSendToCompositorSize;
|
||||
|
||||
// Talos tests for the compositor require at least one frame in the
|
||||
// video queue so that the compositor has something to composit during
|
||||
// the talos test when the decode is stressed. We have a minimum size
|
||||
// on the video queue in order to facilitate this talos test.
|
||||
// Note: Normal playback should not have a queue size of more than 0,
|
||||
// otherwise A/V sync will be ruined! *Only* make this non-zero for
|
||||
// testing purposes.
|
||||
const uint32_t mMinVideoQueueSize;
|
||||
};
|
||||
|
||||
} // namespace media
|
||||
|
@ -21,6 +21,7 @@ with Files('GetUserMedia*'):
|
||||
|
||||
DIRS += [
|
||||
'encoder',
|
||||
'flac',
|
||||
'gmp',
|
||||
'gmp-plugin',
|
||||
'gmp-plugin-openh264',
|
||||
|
@ -5,13 +5,14 @@
|
||||
#include "nsISupports.idl"
|
||||
#include "nsIVariant.idl"
|
||||
|
||||
[scriptable, builtinclass, uuid(cebcefca-2de1-460d-b253-d0582c50b40f)]
|
||||
[scriptable, builtinclass, uuid(ba3b2e08-1c07-4cd3-8822-f4d7e35ff2ae)]
|
||||
interface nsIMediaDevice : nsISupports
|
||||
{
|
||||
readonly attribute DOMString type;
|
||||
readonly attribute DOMString name;
|
||||
readonly attribute DOMString id;
|
||||
readonly attribute DOMString mediaSource;
|
||||
readonly attribute DOMString rawId;
|
||||
};
|
||||
|
||||
[scriptable, function, uuid(24544878-d35e-4962-8c5f-fb84e97bdfee)]
|
||||
|
@ -49,10 +49,12 @@ OggCodecState::Create(ogg_page* aPage)
|
||||
codecState = new OpusState(aPage);
|
||||
} else if (aPage->body_len > 8 && memcmp(aPage->body, "fishead\0", 8) == 0) {
|
||||
codecState = new SkeletonState(aPage);
|
||||
} else if (aPage->body_len > 5 && memcmp(aPage->body, "\177FLAC", 5) == 0) {
|
||||
codecState = new FlacState(aPage);
|
||||
} else {
|
||||
codecState = new OggCodecState(aPage, false);
|
||||
}
|
||||
return codecState->OggCodecState::Init() ? codecState.forget() : nullptr;
|
||||
return codecState->OggCodecState::InternalInit() ? codecState.forget() : nullptr;
|
||||
}
|
||||
|
||||
OggCodecState::OggCodecState(ogg_page* aBosPage, bool aActive)
|
||||
@ -97,7 +99,7 @@ OggCodecState::ClearUnstamped()
|
||||
}
|
||||
|
||||
bool
|
||||
OggCodecState::Init()
|
||||
OggCodecState::InternalInit()
|
||||
{
|
||||
int ret = ogg_stream_init(&mState, mSerial);
|
||||
return ret == 0;
|
||||
@ -830,7 +832,7 @@ VorbisState::ReconstructVorbisGranulepos()
|
||||
// each packet.
|
||||
|
||||
NS_ASSERTION(mUnstamped.Length() > 0, "Length must be > 0");
|
||||
ogg_packet* last = mUnstamped[mUnstamped.Length()-1];
|
||||
ogg_packet* last = mUnstamped.LastElement();
|
||||
NS_ASSERTION(last->e_o_s || last->granulepos >= 0,
|
||||
"Must know last granulepos!");
|
||||
if (mUnstamped.Length() == 1) {
|
||||
@ -1144,7 +1146,7 @@ bool
|
||||
OpusState::ReconstructOpusGranulepos(void)
|
||||
{
|
||||
NS_ASSERTION(mUnstamped.Length() > 0, "Must have unstamped packets");
|
||||
ogg_packet* last = mUnstamped[mUnstamped.Length()-1];
|
||||
ogg_packet* last = mUnstamped.LastElement();
|
||||
NS_ASSERTION(last->e_o_s || last->granulepos > 0,
|
||||
"Must know last granulepos!");
|
||||
int64_t gp;
|
||||
@ -1230,6 +1232,134 @@ OpusState::ReconstructOpusGranulepos(void)
|
||||
return true;
|
||||
}
|
||||
|
||||
FlacState::FlacState(ogg_page* aBosPage)
|
||||
: OggCodecState(aBosPage, true)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
FlacState::DecodeHeader(ogg_packet* aPacket)
|
||||
{
|
||||
nsAutoRef<ogg_packet> autoRelease(aPacket);
|
||||
|
||||
if (!mParser.DecodeHeaderBlock(aPacket->packet, aPacket->bytes)) {
|
||||
return false;
|
||||
}
|
||||
if (mParser.HasFullMetadata()) {
|
||||
mDoneReadingHeaders = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int64_t
|
||||
FlacState::Time(int64_t granulepos)
|
||||
{
|
||||
if (!mParser.mInfo.IsValid()) {
|
||||
return -1;
|
||||
}
|
||||
CheckedInt64 t =
|
||||
SaferMultDiv(granulepos, USECS_PER_S, mParser.mInfo.mRate);
|
||||
if (!t.isValid()) {
|
||||
return -1;
|
||||
}
|
||||
return t.value();
|
||||
}
|
||||
|
||||
int64_t
|
||||
FlacState::PacketDuration(ogg_packet* aPacket)
|
||||
{
|
||||
return mParser.BlockDuration(aPacket->packet, aPacket->bytes);
|
||||
}
|
||||
|
||||
bool
|
||||
FlacState::IsHeader(ogg_packet* aPacket)
|
||||
{
|
||||
return mParser.IsHeaderBlock(aPacket->packet, aPacket->bytes);
|
||||
}
|
||||
|
||||
nsresult
|
||||
FlacState::PageIn(ogg_page* aPage)
|
||||
{
|
||||
if (!mActive) {
|
||||
return NS_OK;
|
||||
}
|
||||
NS_ASSERTION(static_cast<uint32_t>(ogg_page_serialno(aPage)) == mSerial,
|
||||
"Page must be for this stream!");
|
||||
if (ogg_stream_pagein(&mState, aPage) == -1)
|
||||
return NS_ERROR_FAILURE;
|
||||
bool foundGp;
|
||||
nsresult res = PacketOutUntilGranulepos(foundGp);
|
||||
if (NS_FAILED(res)) {
|
||||
return res;
|
||||
}
|
||||
if (foundGp && mDoneReadingHeaders) {
|
||||
// We've found a packet with a granulepos, and we've loaded our metadata
|
||||
// and initialized our decoder. Determine granulepos of buffered packets.
|
||||
ReconstructFlacGranulepos();
|
||||
for (uint32_t i = 0; i < mUnstamped.Length(); ++i) {
|
||||
ogg_packet* packet = mUnstamped[i];
|
||||
NS_ASSERTION(!IsHeader(packet), "Don't try to recover header packet gp");
|
||||
NS_ASSERTION(packet->granulepos != -1, "Packet must have gp by now");
|
||||
mPackets.Append(packet);
|
||||
}
|
||||
mUnstamped.Clear();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Return a hash table with tag metadata.
|
||||
MetadataTags*
|
||||
FlacState::GetTags()
|
||||
{
|
||||
return mParser.GetTags();
|
||||
}
|
||||
|
||||
const AudioInfo&
|
||||
FlacState::Info()
|
||||
{
|
||||
return mParser.mInfo;
|
||||
}
|
||||
|
||||
bool
|
||||
FlacState::ReconstructFlacGranulepos(void)
|
||||
{
|
||||
NS_ASSERTION(mUnstamped.Length() > 0, "Must have unstamped packets");
|
||||
ogg_packet* last = mUnstamped.LastElement();
|
||||
NS_ASSERTION(last->e_o_s || last->granulepos > 0,
|
||||
"Must know last granulepos!");
|
||||
int64_t gp;
|
||||
|
||||
gp = last->granulepos;
|
||||
// Loop through the packets backwards, subtracting the next
|
||||
// packet's duration from its granulepos to get the value
|
||||
// for the current packet.
|
||||
for (uint32_t i = mUnstamped.Length() - 1; i > 0; i--) {
|
||||
int offset =
|
||||
mParser.BlockDuration(mUnstamped[i]->packet, mUnstamped[i]->bytes);
|
||||
// Check for error (negative offset) and overflow.
|
||||
if (offset >= 0) {
|
||||
if (offset <= gp) {
|
||||
gp -= offset;
|
||||
} else {
|
||||
// If the granule position of the first data page is smaller than the
|
||||
// number of decodable audio samples on that page, then we MUST reject
|
||||
// the stream.
|
||||
if (!mDoneReadingHeaders) {
|
||||
return false;
|
||||
}
|
||||
// It's too late to reject the stream.
|
||||
// If we get here, this almost certainly means the file has screwed-up
|
||||
// timestamps somewhere after the first page.
|
||||
NS_WARNING("Clamping negative granulepos to zero.");
|
||||
gp = 0;
|
||||
}
|
||||
}
|
||||
mUnstamped[i - 1]->granulepos = gp;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
SkeletonState::SkeletonState(ogg_page* aBosPage)
|
||||
: OggCodecState(aBosPage, true)
|
||||
, mVersion(0)
|
||||
@ -1666,6 +1796,5 @@ SkeletonState::DecodeHeader(ogg_packet* aPacket)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <nsTArray.h>
|
||||
#include <nsClassHashtable.h>
|
||||
#include "VideoUtils.h"
|
||||
#include "FlacFrameParser.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
@ -85,10 +86,11 @@ public:
|
||||
enum CodecType
|
||||
{
|
||||
TYPE_VORBIS=0,
|
||||
TYPE_THEORA=1,
|
||||
TYPE_OPUS=2,
|
||||
TYPE_SKELETON=3,
|
||||
TYPE_UNKNOWN=4
|
||||
TYPE_THEORA,
|
||||
TYPE_OPUS,
|
||||
TYPE_SKELETON,
|
||||
TYPE_FLAC,
|
||||
TYPE_UNKNOWN
|
||||
};
|
||||
|
||||
virtual ~OggCodecState();
|
||||
@ -141,7 +143,7 @@ public:
|
||||
}
|
||||
|
||||
// Initializes the codec state.
|
||||
virtual bool Init();
|
||||
virtual bool Init() { return true; }
|
||||
|
||||
// Returns true when this bitstream has finished reading all its
|
||||
// header packets.
|
||||
@ -226,6 +228,16 @@ public:
|
||||
// True when all headers packets have been read.
|
||||
bool mDoneReadingHeaders;
|
||||
|
||||
// Validation utility for vorbis-style tag names.
|
||||
static bool IsValidVorbisTagName(nsCString& aName);
|
||||
|
||||
// Utility method to parse and add a vorbis-style comment
|
||||
// to a metadata hash table. Most Ogg-encapsulated codecs
|
||||
// use the vorbis comment format for metadata.
|
||||
static bool AddVorbisComment(MetadataTags* aTags,
|
||||
const char* aComment,
|
||||
uint32_t aLength);
|
||||
|
||||
protected:
|
||||
// Constructs a new OggCodecState. aActive denotes whether the stream is
|
||||
// active. For streams of unsupported or unknown types, aActive should be
|
||||
@ -248,15 +260,8 @@ protected:
|
||||
// in order to capture granulepos.
|
||||
nsTArray<ogg_packet*> mUnstamped;
|
||||
|
||||
// Validation utility for vorbis-style tag names.
|
||||
static bool IsValidVorbisTagName(nsCString& aName);
|
||||
|
||||
// Utility method to parse and add a vorbis-style comment
|
||||
// to a metadata hash table. Most Ogg-encapsulated codecs
|
||||
// use the vorbis comment format for metadata.
|
||||
static bool AddVorbisComment(MetadataTags* aTags,
|
||||
const char* aComment,
|
||||
uint32_t aLength);
|
||||
private:
|
||||
bool InternalInit();
|
||||
};
|
||||
|
||||
class VorbisState : public OggCodecState
|
||||
@ -470,7 +475,6 @@ public:
|
||||
CodecType GetType() override { return TYPE_SKELETON; }
|
||||
bool DecodeHeader(ogg_packet* aPacket) override;
|
||||
int64_t Time(int64_t granulepos) override { return -1; }
|
||||
bool Init() override { return true; }
|
||||
bool IsHeader(ogg_packet* aPacket) override { return true; }
|
||||
|
||||
// Return true if the given time (in milliseconds) is within
|
||||
@ -603,6 +607,29 @@ private:
|
||||
nsClassHashtable<nsUint32HashKey, nsKeyFrameIndex> mIndex;
|
||||
};
|
||||
|
||||
class FlacState : public OggCodecState
|
||||
{
|
||||
public:
|
||||
explicit FlacState(ogg_page* aBosPage);
|
||||
|
||||
CodecType GetType() override { return TYPE_FLAC; }
|
||||
bool DecodeHeader(ogg_packet* aPacket) override;
|
||||
int64_t Time(int64_t granulepos) override;
|
||||
int64_t PacketDuration(ogg_packet* aPacket) override;
|
||||
bool IsHeader(ogg_packet* aPacket) override;
|
||||
nsresult PageIn(ogg_page* aPage) override;
|
||||
|
||||
// Return a hash table with tag metadata.
|
||||
MetadataTags* GetTags() override;
|
||||
|
||||
const AudioInfo& Info();
|
||||
|
||||
private:
|
||||
bool ReconstructFlacGranulepos(void);
|
||||
|
||||
FlacFrameParser mParser;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
// This allows the use of nsAutoRefs for an ogg_packet that properly free the
|
||||
|
@ -4,19 +4,19 @@
|
||||
* 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 "mozilla/Preferences.h"
|
||||
#include "MediaPrefs.h"
|
||||
#include "MediaDecoderStateMachine.h"
|
||||
#include "MediaFormatReader.h"
|
||||
#include "OggDemuxer.h"
|
||||
#include "OggReader.h"
|
||||
#include "OggDecoder.h"
|
||||
#include "nsContentTypeParser.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
MediaDecoderStateMachine* OggDecoder::CreateStateMachine()
|
||||
{
|
||||
bool useFormatDecoder =
|
||||
Preferences::GetBool("media.format-reader.ogg", true);
|
||||
bool useFormatDecoder = MediaPrefs::OggFormatReader();
|
||||
RefPtr<OggDemuxer> demuxer =
|
||||
useFormatDecoder ? new OggDemuxer(GetResource()) : nullptr;
|
||||
RefPtr<MediaDecoderReader> reader = useFormatDecoder
|
||||
@ -29,4 +29,57 @@ MediaDecoderStateMachine* OggDecoder::CreateStateMachine()
|
||||
return new MediaDecoderStateMachine(this, reader);
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
OggDecoder::IsEnabled()
|
||||
{
|
||||
return MediaPrefs::OggEnabled();
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
OggDecoder::CanHandleMediaType(const nsACString& aMIMETypeExcludingCodecs,
|
||||
const nsAString& aCodecs)
|
||||
{
|
||||
if (!IsEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool isOggAudio = aMIMETypeExcludingCodecs.EqualsASCII("audio/ogg");
|
||||
const bool isOggVideo =
|
||||
aMIMETypeExcludingCodecs.EqualsASCII("video/ogg") ||
|
||||
aMIMETypeExcludingCodecs.EqualsASCII("application/ogg");
|
||||
|
||||
if (!isOggAudio && !isOggVideo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsTArray<nsCString> codecMimes;
|
||||
if (aCodecs.IsEmpty()) {
|
||||
// WebM guarantees that the only codecs it contained are vp8, vp9, opus or vorbis.
|
||||
return true;
|
||||
}
|
||||
// Verify that all the codecs specified are ones that we expect that
|
||||
// we can play.
|
||||
nsTArray<nsString> codecs;
|
||||
if (!ParseCodecsString(aCodecs, codecs)) {
|
||||
return false;
|
||||
}
|
||||
for (const nsString& codec : codecs) {
|
||||
if ((IsOpusEnabled() && codec.EqualsLiteral("opus")) ||
|
||||
codec.EqualsLiteral("vorbis") ||
|
||||
(MediaPrefs::FlacInOgg() && codec.EqualsLiteral("flac"))) {
|
||||
continue;
|
||||
}
|
||||
// Note: Only accept Theora in a video content type, not in an audio
|
||||
// content type.
|
||||
if (isOggVideo && codec.EqualsLiteral("theora")) {
|
||||
continue;
|
||||
}
|
||||
// Some unsupported codec.
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -37,6 +37,14 @@ public:
|
||||
return mShutdownBit;
|
||||
}
|
||||
|
||||
// Returns true if aMIMEType is a type that we think we can render with the
|
||||
// a platform decoder backend. If aCodecs is non emtpy, it is filled
|
||||
// with a comma-delimited list of codecs to check support for.
|
||||
static bool CanHandleMediaType(const nsACString& aMIMETypeExcludingCodecs,
|
||||
const nsAString& aCodecs);
|
||||
|
||||
static bool IsEnabled();
|
||||
|
||||
protected:
|
||||
void ShutdownBitChanged() override
|
||||
{
|
||||
|
@ -10,13 +10,13 @@
|
||||
#include "OggDemuxer.h"
|
||||
#include "OggCodecState.h"
|
||||
#include "mozilla/PodOperations.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/SharedThreadPool.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "MediaDataDemuxer.h"
|
||||
#include "nsAutoRef.h"
|
||||
#include "XiphExtradata.h"
|
||||
#include "MediaPrefs.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@ -127,6 +127,7 @@ OggDemuxer::OggDemuxer(MediaResource* aResource)
|
||||
: mTheoraState(nullptr)
|
||||
, mVorbisState(nullptr)
|
||||
, mOpusState(nullptr)
|
||||
, mFlacState(nullptr)
|
||||
, mOpusEnabled(MediaDecoder::IsOpusEnabled())
|
||||
, mSkeletonState(nullptr)
|
||||
, mAudioOggState(aResource)
|
||||
@ -134,6 +135,7 @@ OggDemuxer::OggDemuxer(MediaResource* aResource)
|
||||
, mVorbisSerial(0)
|
||||
, mOpusSerial(0)
|
||||
, mTheoraSerial(0)
|
||||
, mFlacSerial(0)
|
||||
, mOpusPreSkip(0)
|
||||
, mIsChained(false)
|
||||
, mTimedMetadataEvent(nullptr)
|
||||
@ -173,7 +175,7 @@ bool
|
||||
OggDemuxer::HasAudio()
|
||||
const
|
||||
{
|
||||
return mVorbisState || mOpusState;
|
||||
return mVorbisState || mOpusState || mFlacState;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -249,8 +251,10 @@ OggDemuxer::GetTrackCodecState(TrackInfo::TrackType aType) const
|
||||
case TrackInfo::kAudioTrack:
|
||||
if (mVorbisState) {
|
||||
return mVorbisState;
|
||||
} else {
|
||||
} else if (mOpusState) {
|
||||
return mOpusState;
|
||||
} else {
|
||||
return mFlacState;
|
||||
}
|
||||
case TrackInfo::kVideoTrack:
|
||||
return mTheoraState;
|
||||
@ -267,6 +271,7 @@ OggDemuxer::GetCodecStateType(OggCodecState* aState) const
|
||||
return TrackInfo::kVideoTrack;
|
||||
case OggCodecState::TYPE_OPUS:
|
||||
case OggCodecState::TYPE_VORBIS:
|
||||
case OggCodecState::TYPE_FLAC:
|
||||
return TrackInfo::kAudioTrack;
|
||||
default:
|
||||
return TrackInfo::kUndefinedTrack;
|
||||
@ -461,6 +466,18 @@ OggDemuxer::SetupTargetOpus(OpusState* aOpusState, OggHeaders& aHeaders)
|
||||
mOpusPreSkip = aOpusState->mPreSkip;
|
||||
}
|
||||
|
||||
void
|
||||
OggDemuxer::SetupTargetFlac(FlacState* aFlacState, OggHeaders& aHeaders)
|
||||
{
|
||||
if (mFlacState) {
|
||||
mFlacState->Reset();
|
||||
}
|
||||
|
||||
mInfo.mAudio = aFlacState->Info();
|
||||
mFlacState = aFlacState;
|
||||
mFlacSerial = aFlacState->mSerial;
|
||||
}
|
||||
|
||||
void
|
||||
OggDemuxer::SetupTargetSkeleton()
|
||||
{
|
||||
@ -557,6 +574,18 @@ OggDemuxer::SetupMediaTracksInfo(const nsTArray<uint32_t>& aSerials)
|
||||
mInfo.mAudio.mRate = opusState->mRate;
|
||||
mInfo.mAudio.mChannels = opusState->mChannels;
|
||||
FillTags(&mInfo.mAudio, opusState->GetTags());
|
||||
} else if (codecState->GetType() == OggCodecState::TYPE_FLAC) {
|
||||
FlacState* flacState = static_cast<FlacState*>(codecState);
|
||||
if (!(mFlacState && mFlacState->mSerial == flacState->mSerial)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (msgInfo) {
|
||||
InitTrack(msgInfo, &mInfo.mAudio, mFlacState == flacState);
|
||||
}
|
||||
|
||||
mInfo.mAudio = flacState->Info();
|
||||
FillTags(&mInfo.mAudio, flacState->GetTags());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -662,6 +691,15 @@ OggDemuxer::ReadMetadata()
|
||||
NS_WARNING("Opus decoding disabled."
|
||||
" See media.opus.enabled in about:config");
|
||||
}
|
||||
} else if (MediaPrefs::FlacInOgg() &&
|
||||
s->GetType() == OggCodecState::TYPE_FLAC &&
|
||||
ReadHeaders(TrackInfo::kAudioTrack, s, headers)) {
|
||||
if (!mFlacState) {
|
||||
FlacState* flacState = static_cast<FlacState*>(s);
|
||||
SetupTargetFlac(flacState, headers);
|
||||
} else {
|
||||
s->Deactivate();
|
||||
}
|
||||
} else if (s->GetType() == OggCodecState::TYPE_SKELETON && !mSkeletonState) {
|
||||
mSkeletonState = static_cast<SkeletonState*>(s);
|
||||
} else {
|
||||
@ -735,6 +773,7 @@ OggDemuxer::ReadOggChain(const media::TimeUnit& aLastEndTime)
|
||||
bool chained = false;
|
||||
OpusState* newOpusState = nullptr;
|
||||
VorbisState* newVorbisState = nullptr;
|
||||
FlacState* newFlacState = nullptr;
|
||||
nsAutoPtr<MetadataTags> tags;
|
||||
|
||||
if (HasVideo() || HasSkeleton() || !HasAudio()) {
|
||||
@ -762,6 +801,8 @@ OggDemuxer::ReadOggChain(const media::TimeUnit& aLastEndTime)
|
||||
newVorbisState = static_cast<VorbisState*>(codecState.get());
|
||||
} else if (mOpusState && (codecState->GetType() == OggCodecState::TYPE_OPUS)) {
|
||||
newOpusState = static_cast<OpusState*>(codecState.get());
|
||||
} else if (mFlacState && (codecState->GetType() == OggCodecState::TYPE_FLAC)) {
|
||||
newFlacState = static_cast<FlacState*>(codecState.get());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@ -821,6 +862,24 @@ OggDemuxer::ReadOggChain(const media::TimeUnit& aLastEndTime)
|
||||
tags = newOpusState->GetTags();
|
||||
}
|
||||
|
||||
OggHeaders flacHeaders;
|
||||
if ((newFlacState &&
|
||||
ReadHeaders(TrackInfo::kAudioTrack, newFlacState, flacHeaders)) &&
|
||||
(mFlacState->Info().mRate == newFlacState->Info().mRate) &&
|
||||
(mFlacState->Info().mChannels == newFlacState->Info().mChannels)) {
|
||||
|
||||
SetupTargetFlac(newFlacState, flacHeaders);
|
||||
LOG(LogLevel::Debug, ("New flac ogg link, serial=%d\n", mFlacSerial));
|
||||
|
||||
if (msgInfo) {
|
||||
InitTrack(msgInfo, &mInfo.mAudio, true);
|
||||
}
|
||||
|
||||
mInfo.mAudio = newFlacState->Info();
|
||||
chained = true;
|
||||
tags = newFlacState->GetTags();
|
||||
}
|
||||
|
||||
if (chained) {
|
||||
SetChained();
|
||||
mInfo.mMediaSeekable = false;
|
||||
@ -1057,6 +1116,10 @@ OggDemuxer::GetBuffered(TrackInfo::TrackType aType)
|
||||
serial == mOpusSerial) {
|
||||
startTime = OpusState::Time(mOpusPreSkip, granulepos);
|
||||
NS_ASSERTION(startTime > 0, "Must have positive start time");
|
||||
} else if (aType == TrackInfo::kAudioTrack && mFlacState &&
|
||||
serial == mFlacSerial) {
|
||||
startTime = mFlacState->Time(granulepos);
|
||||
NS_ASSERTION(startTime > 0, "Must have positive start time");
|
||||
} else if (aType == TrackInfo::kVideoTrack && mTheoraState &&
|
||||
serial == mTheoraSerial) {
|
||||
startTime = TheoraState::Time(&mTheoraInfo, granulepos);
|
||||
@ -2012,6 +2075,8 @@ OggDemuxer::SeekBisection(TrackInfo::TrackType aType,
|
||||
audioTime = mVorbisState->Time(granulepos);
|
||||
} else if (mOpusState && serial == mOpusState->mSerial) {
|
||||
audioTime = mOpusState->Time(granulepos);
|
||||
} else if (mFlacState && serial == mFlacState->mSerial) {
|
||||
audioTime = mFlacState->Time(granulepos);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -220,6 +220,7 @@ private:
|
||||
void SetupTargetTheora(TheoraState* aTheoraState, OggHeaders& aHeaders);
|
||||
void SetupTargetVorbis(VorbisState* aVorbisState, OggHeaders& aHeaders);
|
||||
void SetupTargetOpus(OpusState* aOpusState, OggHeaders& aHeaders);
|
||||
void SetupTargetFlac(FlacState* aFlacState, OggHeaders& aHeaders);
|
||||
void SetupTargetSkeleton();
|
||||
void SetupMediaTracksInfo(const nsTArray<uint32_t>& aSerials);
|
||||
void FillTags(TrackInfo* aInfo, MetadataTags* aTags);
|
||||
@ -264,6 +265,9 @@ private:
|
||||
OpusState* mOpusState;
|
||||
|
||||
// Get the bitstream decode state for the given track type
|
||||
// Decode state of the Flac bitstream we're decoding, if we have one.
|
||||
FlacState* mFlacState;
|
||||
|
||||
OggCodecState* GetTrackCodecState(TrackInfo::TrackType aType) const;
|
||||
TrackInfo::TrackType GetCodecStateType(OggCodecState* aState) const;
|
||||
|
||||
@ -302,6 +306,8 @@ private:
|
||||
uint32_t mVorbisSerial;
|
||||
uint32_t mOpusSerial;
|
||||
uint32_t mTheoraSerial;
|
||||
uint32_t mFlacSerial;
|
||||
|
||||
vorbis_info mVorbisInfo;
|
||||
int mOpusPreSkip;
|
||||
th_info mTheoraInfo;
|
||||
|
@ -21,8 +21,10 @@ FFmpegAudioDecoder<LIBAV_VER>::FFmpegAudioDecoder(FFmpegLibWrapper* aLib,
|
||||
{
|
||||
MOZ_COUNT_CTOR(FFmpegAudioDecoder);
|
||||
// Use a new MediaByteBuffer as the object will be modified during initialization.
|
||||
mExtraData = new MediaByteBuffer;
|
||||
mExtraData->AppendElements(*aConfig.mCodecSpecificConfig);
|
||||
if (aConfig.mCodecSpecificConfig && aConfig.mCodecSpecificConfig->Length()) {
|
||||
mExtraData = new MediaByteBuffer;
|
||||
mExtraData->AppendElements(*aConfig.mCodecSpecificConfig);
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<MediaDataDecoder::InitPromise>
|
||||
@ -91,6 +93,25 @@ CopyAndPackAudio(AVFrame* aFrame, uint32_t aNumChannels, uint32_t aNumAFrames)
|
||||
*tmp++ = AudioSampleToFloat(data[channel][frame]);
|
||||
}
|
||||
}
|
||||
} else if (aFrame->format == AV_SAMPLE_FMT_S32) {
|
||||
// Audio data already packed. Need to convert from S16 to 32 bits Float
|
||||
AudioDataValue* tmp = audio.get();
|
||||
int32_t* data = reinterpret_cast<int32_t**>(aFrame->data)[0];
|
||||
for (uint32_t frame = 0; frame < aNumAFrames; frame++) {
|
||||
for (uint32_t channel = 0; channel < aNumChannels; channel++) {
|
||||
*tmp++ = AudioSampleToFloat(*data++);
|
||||
}
|
||||
}
|
||||
} else if (aFrame->format == AV_SAMPLE_FMT_S32P) {
|
||||
// Planar audio data. Convert it from S32 to 32 bits float
|
||||
// and pack it into something we can understand.
|
||||
AudioDataValue* tmp = audio.get();
|
||||
int32_t** data = reinterpret_cast<int32_t**>(aFrame->data);
|
||||
for (uint32_t frame = 0; frame < aNumAFrames; frame++) {
|
||||
for (uint32_t channel = 0; channel < aNumChannels; channel++) {
|
||||
*tmp++ = AudioSampleToFloat(data[channel][frame]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return audio;
|
||||
@ -123,6 +144,16 @@ FFmpegAudioDecoder<LIBAV_VER>::DoDecode(MediaRawData* aSample)
|
||||
return DecodeResult::DECODE_ERROR;
|
||||
}
|
||||
|
||||
if (mFrame->format != AV_SAMPLE_FMT_FLT &&
|
||||
mFrame->format != AV_SAMPLE_FMT_FLTP &&
|
||||
mFrame->format != AV_SAMPLE_FMT_S16 &&
|
||||
mFrame->format != AV_SAMPLE_FMT_S16P &&
|
||||
mFrame->format != AV_SAMPLE_FMT_S32 &&
|
||||
mFrame->format != AV_SAMPLE_FMT_S32P) {
|
||||
NS_WARNING("FFmpeg audio decoder outputs unsupported audio format.");
|
||||
return DecodeResult::DECODE_ERROR;
|
||||
}
|
||||
|
||||
if (decoded) {
|
||||
uint32_t numChannels = mCodecContext->channels;
|
||||
AudioConfig::ChannelLayout layout(numChannels);
|
||||
@ -176,9 +207,9 @@ FFmpegAudioDecoder<LIBAV_VER>::GetCodecId(const nsACString& aMimeType)
|
||||
{
|
||||
if (aMimeType.EqualsLiteral("audio/mpeg")) {
|
||||
return AV_CODEC_ID_MP3;
|
||||
}
|
||||
|
||||
if (aMimeType.EqualsLiteral("audio/mp4a-latm")) {
|
||||
} else if (aMimeType.EqualsLiteral("audio/flac")) {
|
||||
return AV_CODEC_ID_FLAC;
|
||||
} else if (aMimeType.EqualsLiteral("audio/mp4a-latm")) {
|
||||
return AV_CODEC_ID_AAC;
|
||||
}
|
||||
|
||||
|
@ -86,15 +86,6 @@ FFmpegDataDecoder<LIBAV_VER>::InitDecoder()
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (mCodecContext->codec_type == AVMEDIA_TYPE_AUDIO &&
|
||||
mCodecContext->sample_fmt != AV_SAMPLE_FMT_FLT &&
|
||||
mCodecContext->sample_fmt != AV_SAMPLE_FMT_FLTP &&
|
||||
mCodecContext->sample_fmt != AV_SAMPLE_FMT_S16 &&
|
||||
mCodecContext->sample_fmt != AV_SAMPLE_FMT_S16P) {
|
||||
NS_WARNING("FFmpeg audio decoder outputs unsupported audio format.");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
FFMPEG_LOG("FFmpeg init successful.");
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -45,35 +45,24 @@ public:
|
||||
already_AddRefed<MediaDataDecoder>
|
||||
CreateAudioDecoder(const CreateDecoderParams& aParams) override
|
||||
{
|
||||
#ifdef USING_MOZFFVPX
|
||||
return nullptr;
|
||||
#else
|
||||
RefPtr<MediaDataDecoder> decoder =
|
||||
new FFmpegAudioDecoder<V>(mLib,
|
||||
aParams.mTaskQueue,
|
||||
aParams.mCallback,
|
||||
aParams.AudioConfig());
|
||||
return decoder.forget();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SupportsMimeType(const nsACString& aMimeType,
|
||||
DecoderDoctorDiagnostics* aDiagnostics) const override
|
||||
{
|
||||
AVCodecID videoCodec = FFmpegVideoDecoder<V>::GetCodecId(aMimeType);
|
||||
#ifdef USING_MOZFFVPX
|
||||
if (videoCodec == AV_CODEC_ID_NONE) {
|
||||
return false;
|
||||
}
|
||||
return !!FFmpegDataDecoder<V>::FindAVCodec(mLib, videoCodec);
|
||||
#else
|
||||
AVCodecID audioCodec = FFmpegAudioDecoder<V>::GetCodecId(aMimeType);
|
||||
if (audioCodec == AV_CODEC_ID_NONE && videoCodec == AV_CODEC_ID_NONE) {
|
||||
return false;
|
||||
}
|
||||
AVCodecID codec = audioCodec != AV_CODEC_ID_NONE ? audioCodec : videoCodec;
|
||||
return !!FFmpegDataDecoder<V>::FindAVCodec(mLib, codec);
|
||||
#endif
|
||||
}
|
||||
|
||||
ConversionRequired
|
||||
|
@ -26,6 +26,7 @@ extern "C" {
|
||||
#define AV_CODEC_ID_MP3 CODEC_ID_MP3
|
||||
#define AV_CODEC_ID_VP8 CODEC_ID_VP8
|
||||
#define AV_CODEC_ID_NONE CODEC_ID_NONE
|
||||
#define AV_CODEC_ID_FLAC CODEC_ID_FLAC
|
||||
typedef CodecID AVCodecID;
|
||||
#endif
|
||||
|
||||
|
@ -10,6 +10,7 @@ EXPORTS += [
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'../FFmpegAudioDecoder.cpp',
|
||||
'../FFmpegDataDecoder.cpp',
|
||||
'../FFmpegDecoderModule.cpp',
|
||||
'../FFmpegVideoDecoder.cpp',
|
||||
|
BIN
dom/media/test/A4.ogv
Normal file
BIN
dom/media/test/A4.ogv
Normal file
Binary file not shown.
1
dom/media/test/A4.ogv^headers^
Normal file
1
dom/media/test/A4.ogv^headers^
Normal file
@ -0,0 +1 @@
|
||||
Cache-Control: no-store
|
BIN
dom/media/test/flac-noheader-s16.flac
Executable file
BIN
dom/media/test/flac-noheader-s16.flac
Executable file
Binary file not shown.
1
dom/media/test/flac-noheader-s16.flac^headers^
Normal file
1
dom/media/test/flac-noheader-s16.flac^headers^
Normal file
@ -0,0 +1 @@
|
||||
Cache-Control: no-store
|
BIN
dom/media/test/flac-s24.flac
Normal file
BIN
dom/media/test/flac-s24.flac
Normal file
Binary file not shown.
1
dom/media/test/flac-s24.flac^headers^
Normal file
1
dom/media/test/flac-s24.flac^headers^
Normal file
@ -0,0 +1 @@
|
||||
Cache-Control: no-store
|
@ -36,6 +36,7 @@ var gSmallTests = [
|
||||
{ name:"vp9.webm", type:"video/webm", width:320, height:240, duration:4 },
|
||||
{ name:"detodos.opus", type:"audio/ogg; codecs=opus", duration:2.9135 },
|
||||
{ name:"gizmo.mp4", type:"video/mp4", width:560, height:320, duration:5.56 },
|
||||
{ name:"flac-s24.flac", type:"audio/flac", duration:4.04 },
|
||||
{ name:"bogus.duh", type:"bogus/duh" }
|
||||
];
|
||||
|
||||
@ -86,7 +87,7 @@ var gPlayedTests = [
|
||||
// Disable vbr.mp3 to see if it reduces the error of AUDCLNT_E_CPUUSAGE_EXCEEDED.
|
||||
// See bug 1110922 comment 26.
|
||||
//{ name:"vbr.mp3", type:"audio/mpeg", duration:10.0 },
|
||||
{ name:"bug495794.ogg", type:"audio/ogg", duration:0.3 }
|
||||
{ name:"bug495794.ogg", type:"audio/ogg", duration:0.3 },
|
||||
];
|
||||
|
||||
// Used by test_mozLoadFrom. Need one test file per decoder backend, plus
|
||||
@ -119,6 +120,7 @@ var gTrackTests = [
|
||||
{ name:"320x240.ogv", type:"video/ogg", width:320, height:240, duration:0.266, size:28942, hasAudio:false, hasVideo:true },
|
||||
{ name:"short-video.ogv", type:"video/ogg", duration:1.081, hasAudio:true, hasVideo:true },
|
||||
{ name:"seek.webm", type:"video/webm", duration:3.966, size:215529, hasAudio:false, hasVideo:true },
|
||||
{ name:"flac-s24.flac", type:"audio/flac", duration:4.04, hasAudio:true, hasVideo:false },
|
||||
{ name:"bogus.duh", type:"bogus/duh" }
|
||||
];
|
||||
|
||||
@ -272,6 +274,13 @@ var gPlayTests = [
|
||||
// trust the header, so this should be reported as 10 seconds.
|
||||
{ name:"vbr-head.mp3", type:"audio/mpeg", duration:10.00 },
|
||||
|
||||
// A flac file where the STREAMINFO block was removed.
|
||||
// It is necessary to parse the file to find an audio frame instead.
|
||||
{ name:"flac-noheader-s16.flac", type:"audio/flac", duration:4.0 },
|
||||
{ name:"flac-s24.flac", type:"audio/flac", duration:4.04 },
|
||||
// Ogg with theora video and flac audio.
|
||||
{ name:"A4.ogv", type:"video/ogg", width:320, height:240, duration:3.13 },
|
||||
|
||||
// Invalid file
|
||||
{ name:"bogus.duh", type:"bogus/duh", duration:Number.NaN },
|
||||
];
|
||||
@ -760,6 +769,15 @@ var gMetadataTests = [
|
||||
},
|
||||
{ name:"wavedata_u8.wav", tags: { }
|
||||
},
|
||||
{ name:"flac-s24.flac", tags: {
|
||||
ALBUM:"Seascapes",
|
||||
TITLE:"(La Mer) - II. Jeux de vagues. Allegro",
|
||||
COMPOSER:"Debussy, Claude",
|
||||
TRACKNUMBER:"2/9",
|
||||
DISCNUMBER:"1/1",
|
||||
encoder:"Lavf57.41.100",
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
// Test files for Encrypted Media Extensions
|
||||
|
@ -31,6 +31,8 @@ support-files =
|
||||
320x240.ogv^headers^
|
||||
448636.ogv
|
||||
448636.ogv^headers^
|
||||
A4.ogv
|
||||
A4.ogv^headers^
|
||||
VID_0001.ogg
|
||||
VID_0001.ogg^headers^
|
||||
allowed.sjs
|
||||
@ -411,6 +413,10 @@ support-files =
|
||||
dynamic_resource.sjs
|
||||
eme.js
|
||||
file_access_controls.html
|
||||
flac-s24.flac
|
||||
flac-s24.flac^headers^
|
||||
flac-noheader-s16.flac
|
||||
flac-noheader-s16.flac^headers^
|
||||
fragment_noplay.js
|
||||
fragment_play.js
|
||||
gizmo.mp4
|
||||
|
@ -498,6 +498,11 @@ PushSubscription.prototype = {
|
||||
return !!this._props.systemRecord;
|
||||
},
|
||||
|
||||
/** The private key used to decrypt incoming push messages, in JWK format */
|
||||
get p256dhPrivateKey() {
|
||||
return this._props.p256dhPrivateKey;
|
||||
},
|
||||
|
||||
/**
|
||||
* Indicates whether this subscription is subject to the background message
|
||||
* quota.
|
||||
|
@ -276,6 +276,7 @@ PushRecord.prototype = {
|
||||
lastPush: this.lastPush,
|
||||
pushCount: this.pushCount,
|
||||
p256dhKey: this.p256dhPublicKey,
|
||||
p256dhPrivateKey: this.p256dhPrivateKey,
|
||||
authenticationSecret: this.authenticationSecret,
|
||||
appServerKey: this.appServerKey,
|
||||
quota: this.quotaApplies() ? this.quota : -1,
|
||||
|
@ -871,17 +871,16 @@ this.PushService = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Decrypts an incoming message and notifies the associated service worker.
|
||||
* Decrypts a message. Will resolve with null if cryptoParams is falsy.
|
||||
*
|
||||
* @param {PushRecord} record The receiving registration.
|
||||
* @param {String} messageID The message ID.
|
||||
* @param {ArrayBuffer|Uint8Array} data The encrypted message data.
|
||||
* @param {Object} cryptoParams The message encryption settings.
|
||||
* @returns {Promise} Resolves with an ack status code.
|
||||
* @returns {Promise} Resolves with the decrypted message.
|
||||
*/
|
||||
_decryptAndNotifyApp(record, messageID, data, cryptoParams) {
|
||||
_decryptMessage(data, record, cryptoParams) {
|
||||
if (!cryptoParams) {
|
||||
return this._notifyApp(record, messageID, null);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
return PushCrypto.decodeMsg(
|
||||
data,
|
||||
@ -892,13 +891,29 @@ this.PushService = {
|
||||
cryptoParams.rs,
|
||||
record.authenticationSecret,
|
||||
cryptoParams.padSize
|
||||
).then(message => this._notifyApp(record, messageID, message), error => {
|
||||
let message = gDOMBundle.formatStringFromName(
|
||||
"PushMessageDecryptionFailure", [record.scope, String(error)], 2);
|
||||
gPushNotifier.notifyError(record.scope, record.principal, message,
|
||||
Ci.nsIScriptError.errorFlag);
|
||||
return Ci.nsIPushErrorReporter.ACK_DECRYPTION_ERROR;
|
||||
});
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Decrypts an incoming message and notifies the associated service worker.
|
||||
*
|
||||
* @param {PushRecord} record The receiving registration.
|
||||
* @param {String} messageID The message ID.
|
||||
* @param {ArrayBuffer|Uint8Array} data The encrypted message data.
|
||||
* @param {Object} cryptoParams The message encryption settings.
|
||||
* @returns {Promise} Resolves with an ack status code.
|
||||
*/
|
||||
_decryptAndNotifyApp(record, messageID, data, cryptoParams) {
|
||||
return this._decryptMessage(data, record, cryptoParams)
|
||||
.then(
|
||||
message => this._notifyApp(record, messageID, message),
|
||||
error => {
|
||||
let message = gDOMBundle.formatStringFromName(
|
||||
"PushMessageDecryptionFailure", [record.scope, String(error)], 2);
|
||||
gPushNotifier.notifyError(record.scope, record.principal, message,
|
||||
Ci.nsIScriptError.errorFlag);
|
||||
return Ci.nsIPushErrorReporter.ACK_DECRYPTION_ERROR;
|
||||
});
|
||||
},
|
||||
|
||||
_updateQuota: function(keyID) {
|
||||
|
@ -12,7 +12,11 @@ const Cr = Components.results;
|
||||
|
||||
const {PushDB} = Cu.import("resource://gre/modules/PushDB.jsm");
|
||||
const {PushRecord} = Cu.import("resource://gre/modules/PushRecord.jsm");
|
||||
Cu.import("resource://gre/modules/Messaging.jsm"); /*global: Services */
|
||||
const {
|
||||
PushCrypto,
|
||||
getCryptoParams,
|
||||
} = Cu.import("resource://gre/modules/PushCrypto.jsm");
|
||||
Cu.import("resource://gre/modules/Messaging.jsm"); /*global: Messaging */
|
||||
Cu.import("resource://gre/modules/Services.jsm"); /*global: Services */
|
||||
Cu.import("resource://gre/modules/Preferences.jsm"); /*global: Preferences */
|
||||
Cu.import("resource://gre/modules/Promise.jsm"); /*global: Promise */
|
||||
@ -20,12 +24,6 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm"); /*global: XPCOMUtils */
|
||||
|
||||
const Log = Cu.import("resource://gre/modules/AndroidLog.jsm", {}).AndroidLog.bind("Push");
|
||||
|
||||
const {
|
||||
PushCrypto,
|
||||
concatArray,
|
||||
getCryptoParams,
|
||||
} = Cu.import("resource://gre/modules/PushCrypto.jsm");
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["PushServiceAndroidGCM"];
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "console", () => {
|
||||
@ -41,6 +39,8 @@ const kPUSHANDROIDGCMDB_DB_NAME = "pushAndroidGCM";
|
||||
const kPUSHANDROIDGCMDB_DB_VERSION = 5; // Change this if the IndexedDB format changes
|
||||
const kPUSHANDROIDGCMDB_STORE_NAME = "pushAndroidGCM";
|
||||
|
||||
const FXA_PUSH_SCOPE = "chrome://fxa-push";
|
||||
|
||||
const prefs = new Preferences("dom.push.");
|
||||
|
||||
/**
|
||||
@ -76,57 +76,67 @@ this.PushServiceAndroidGCM = {
|
||||
},
|
||||
|
||||
observe: function(subject, topic, data) {
|
||||
if (topic == "nsPref:changed") {
|
||||
if (data == "dom.push.debug") {
|
||||
// Reconfigure.
|
||||
let debug = !!prefs.get("debug");
|
||||
console.info("Debug parameter changed; updating configuration with new debug", debug);
|
||||
this._configure(this._serverURI, debug);
|
||||
}
|
||||
switch (topic) {
|
||||
case "nsPref:changed":
|
||||
if (data == "dom.push.debug") {
|
||||
// Reconfigure.
|
||||
let debug = !!prefs.get("debug");
|
||||
console.info("Debug parameter changed; updating configuration with new debug", debug);
|
||||
this._configure(this._serverURI, debug);
|
||||
}
|
||||
break;
|
||||
case "PushServiceAndroidGCM:ReceivedPushMessage":
|
||||
this._onPushMessageReceived(data);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_onPushMessageReceived(data) {
|
||||
// TODO: Use Messaging.jsm for this.
|
||||
if (this._mainPushService == null) {
|
||||
// Shouldn't ever happen, but let's be careful.
|
||||
console.error("No main PushService! Dropping message.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (topic == "PushServiceAndroidGCM:ReceivedPushMessage") {
|
||||
// TODO: Use Messaging.jsm for this.
|
||||
if (this._mainPushService == null) {
|
||||
// Shouldn't ever happen, but let's be careful.
|
||||
console.error("No main PushService! Dropping message.");
|
||||
return;
|
||||
}
|
||||
if (!data) {
|
||||
console.error("No data from Java! Dropping message.");
|
||||
return;
|
||||
}
|
||||
data = JSON.parse(data);
|
||||
console.debug("ReceivedPushMessage with data", data);
|
||||
|
||||
// Default is no data (and no encryption).
|
||||
let message = null;
|
||||
let cryptoParams = null;
|
||||
|
||||
if (data.message && data.enc && (data.enckey || data.cryptokey)) {
|
||||
let headers = {
|
||||
encryption_key: data.enckey,
|
||||
crypto_key: data.cryptokey,
|
||||
encryption: data.enc,
|
||||
encoding: data.con,
|
||||
};
|
||||
cryptoParams = getCryptoParams(headers);
|
||||
// Ciphertext is (urlsafe) Base 64 encoded.
|
||||
message = ChromeUtils.base64URLDecode(data.message, {
|
||||
// The Push server may append padding.
|
||||
padding: "ignore",
|
||||
});
|
||||
}
|
||||
|
||||
console.debug("Delivering message to main PushService:", message, cryptoParams);
|
||||
this._mainPushService.receivedPushMessage(
|
||||
data.channelID, "", message, cryptoParams, (record) => {
|
||||
// Always update the stored record.
|
||||
return record;
|
||||
});
|
||||
if (!data) {
|
||||
console.error("No data from Java! Dropping message.");
|
||||
return;
|
||||
}
|
||||
data = JSON.parse(data);
|
||||
console.debug("ReceivedPushMessage with data", data);
|
||||
|
||||
let { message, cryptoParams } = this._messageAndCryptoParams(data);
|
||||
|
||||
console.debug("Delivering message to main PushService:", message, cryptoParams);
|
||||
this._mainPushService.receivedPushMessage(
|
||||
data.channelID, "", message, cryptoParams, (record) => {
|
||||
// Always update the stored record.
|
||||
return record;
|
||||
});
|
||||
},
|
||||
|
||||
_messageAndCryptoParams(data) {
|
||||
// Default is no data (and no encryption).
|
||||
let message = null;
|
||||
let cryptoParams = null;
|
||||
|
||||
if (data.message && data.enc && (data.enckey || data.cryptokey)) {
|
||||
let headers = {
|
||||
encryption_key: data.enckey,
|
||||
crypto_key: data.cryptokey,
|
||||
encryption: data.enc,
|
||||
encoding: data.con,
|
||||
};
|
||||
cryptoParams = getCryptoParams(headers);
|
||||
// Ciphertext is (urlsafe) Base 64 encoded.
|
||||
message = ChromeUtils.base64URLDecode(data.message, {
|
||||
// The Push server may append padding.
|
||||
padding: "ignore",
|
||||
});
|
||||
}
|
||||
return { message, cryptoParams };
|
||||
},
|
||||
|
||||
_configure: function(serverURL, debug) {
|
||||
@ -209,11 +219,16 @@ this.PushServiceAndroidGCM = {
|
||||
// The Push server requires padding.
|
||||
pad: true,
|
||||
}) : null;
|
||||
// Caller handles errors.
|
||||
return Messaging.sendRequestForResult({
|
||||
let message = {
|
||||
type: "PushServiceAndroidGCM:SubscribeChannel",
|
||||
appServerKey: appServerKey,
|
||||
}).then(data => {
|
||||
}
|
||||
if (record.scope == FXA_PUSH_SCOPE) {
|
||||
message.service = "fxa";
|
||||
}
|
||||
// Caller handles errors.
|
||||
return Messaging.sendRequestForResult(message)
|
||||
.then(data => {
|
||||
console.debug("Got data:", data);
|
||||
return PushCrypto.generateKeys()
|
||||
.then(exportedKeys =>
|
||||
@ -225,6 +240,7 @@ this.PushServiceAndroidGCM = {
|
||||
scope: record.scope,
|
||||
originAttributes: record.originAttributes,
|
||||
ctime: ctime,
|
||||
systemRecord: record.systemRecord,
|
||||
// Cryptography!
|
||||
p256dhPublicKey: exportedKeys[0],
|
||||
p256dhPrivateKey: exportedKeys[1],
|
||||
|
@ -318,7 +318,7 @@ bool DuplicateHandle(HANDLE aSourceHandle,
|
||||
FALSE,
|
||||
aTargetProcessId));
|
||||
if (!targetProcess) {
|
||||
#ifdef MOZ_CRASH_REPORTER
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
CrashReporter::AnnotateCrashReport(
|
||||
NS_LITERAL_CSTRING("IPCTransportFailureReason"),
|
||||
NS_LITERAL_CSTRING("Failed to open target process."));
|
||||
|
@ -142,7 +142,7 @@ AccessibleCaret::SetSelectionBarEnabled(bool aEnabled)
|
||||
mSelectionBarEnabled = aEnabled;
|
||||
}
|
||||
|
||||
/* static */ nsString
|
||||
/* static */ nsAutoString
|
||||
AccessibleCaret::AppearanceString(Appearance aAppearance)
|
||||
{
|
||||
nsAutoString string;
|
||||
|
@ -181,8 +181,8 @@ protected:
|
||||
|
||||
nsIFrame* CustomContentContainerFrame() const;
|
||||
|
||||
// Transform Appearance to CSS class name in ua.css.
|
||||
static nsString AppearanceString(Appearance aAppearance);
|
||||
// Transform Appearance to CSS id used in ua.css.
|
||||
static nsAutoString AppearanceString(Appearance aAppearance);
|
||||
|
||||
already_AddRefed<dom::Element> CreateCaretElement(nsIDocument* aDocument) const;
|
||||
|
||||
|
@ -3920,10 +3920,10 @@ nsRuleNode::SetFont(nsPresContext* aPresContext, nsStyleContext* aContext,
|
||||
MOZ_ASSERT_UNREACHABLE("Unknown unit for -moz-min-font-size-ratio");
|
||||
}
|
||||
|
||||
// font-size: enum, length, percent, inherit
|
||||
nscoord scriptLevelAdjustedParentSize = aParentFont->mSize;
|
||||
nscoord scriptLevelAdjustedUnconstrainedParentSize;
|
||||
scriptLevelAdjustedParentSize =
|
||||
|
||||
// font-size: enum, length, percent, inherit
|
||||
nscoord scriptLevelAdjustedParentSize =
|
||||
ComputeScriptLevelSize(aFont, aParentFont, aPresContext,
|
||||
&scriptLevelAdjustedUnconstrainedParentSize);
|
||||
NS_ASSERTION(!aUsedStartStruct || aFont->mScriptUnconstrainedSize == aFont->mSize,
|
||||
|
@ -576,11 +576,11 @@
|
||||
#define CONFIG_FAANDCT 0
|
||||
#define CONFIG_FAANIDCT 0
|
||||
#define CONFIG_FDCTDSP 0
|
||||
#define CONFIG_FLACDSP 0
|
||||
#define CONFIG_FLACDSP 1
|
||||
#define CONFIG_FMTCONVERT 0
|
||||
#define CONFIG_FRAME_THREAD_ENCODER 0
|
||||
#define CONFIG_G722DSP 0
|
||||
#define CONFIG_GOLOMB 0
|
||||
#define CONFIG_GOLOMB 1
|
||||
#define CONFIG_GPLV3 0
|
||||
#define CONFIG_H263DSP 0
|
||||
#define CONFIG_H264CHROMA 0
|
||||
@ -922,7 +922,7 @@
|
||||
#define CONFIG_EAC3_DECODER 0
|
||||
#define CONFIG_EVRC_DECODER 0
|
||||
#define CONFIG_FFWAVESYNTH_DECODER 0
|
||||
#define CONFIG_FLAC_DECODER 0
|
||||
#define CONFIG_FLAC_DECODER 1
|
||||
#define CONFIG_G723_1_DECODER 0
|
||||
#define CONFIG_G729_DECODER 0
|
||||
#define CONFIG_GSM_DECODER 0
|
||||
@ -2104,7 +2104,7 @@
|
||||
#define CONFIG_DVBSUB_PARSER 0
|
||||
#define CONFIG_DVDSUB_PARSER 0
|
||||
#define CONFIG_DVD_NAV_PARSER 0
|
||||
#define CONFIG_FLAC_PARSER 0
|
||||
#define CONFIG_FLAC_PARSER 1
|
||||
#define CONFIG_G729_PARSER 0
|
||||
#define CONFIG_GSM_PARSER 0
|
||||
#define CONFIG_H261_PARSER 0
|
||||
|
@ -561,11 +561,11 @@
|
||||
%define CONFIG_FAANDCT 0
|
||||
%define CONFIG_FAANIDCT 0
|
||||
%define CONFIG_FDCTDSP 0
|
||||
%define CONFIG_FLACDSP 0
|
||||
%define CONFIG_FLACDSP 1
|
||||
%define CONFIG_FMTCONVERT 0
|
||||
%define CONFIG_FRAME_THREAD_ENCODER 0
|
||||
%define CONFIG_G722DSP 0
|
||||
%define CONFIG_GOLOMB 0
|
||||
%define CONFIG_GOLOMB 1
|
||||
%define CONFIG_GPLV3 0
|
||||
%define CONFIG_H263DSP 0
|
||||
%define CONFIG_H264CHROMA 0
|
||||
@ -907,7 +907,7 @@
|
||||
%define CONFIG_EAC3_DECODER 0
|
||||
%define CONFIG_EVRC_DECODER 0
|
||||
%define CONFIG_FFWAVESYNTH_DECODER 0
|
||||
%define CONFIG_FLAC_DECODER 0
|
||||
%define CONFIG_FLAC_DECODER 1
|
||||
%define CONFIG_G723_1_DECODER 0
|
||||
%define CONFIG_G729_DECODER 0
|
||||
%define CONFIG_GSM_DECODER 0
|
||||
@ -2089,7 +2089,7 @@
|
||||
%define CONFIG_DVBSUB_PARSER 0
|
||||
%define CONFIG_DVDSUB_PARSER 0
|
||||
%define CONFIG_DVD_NAV_PARSER 0
|
||||
%define CONFIG_FLAC_PARSER 0
|
||||
%define CONFIG_FLAC_PARSER 1
|
||||
%define CONFIG_G729_PARSER 0
|
||||
%define CONFIG_GSM_PARSER 0
|
||||
%define CONFIG_H261_PARSER 0
|
||||
|
@ -576,11 +576,11 @@
|
||||
#define CONFIG_FAANDCT 0
|
||||
#define CONFIG_FAANIDCT 0
|
||||
#define CONFIG_FDCTDSP 0
|
||||
#define CONFIG_FLACDSP 0
|
||||
#define CONFIG_FLACDSP 1
|
||||
#define CONFIG_FMTCONVERT 0
|
||||
#define CONFIG_FRAME_THREAD_ENCODER 0
|
||||
#define CONFIG_G722DSP 0
|
||||
#define CONFIG_GOLOMB 0
|
||||
#define CONFIG_GOLOMB 1
|
||||
#define CONFIG_GPLV3 0
|
||||
#define CONFIG_H263DSP 0
|
||||
#define CONFIG_H264CHROMA 0
|
||||
@ -922,7 +922,7 @@
|
||||
#define CONFIG_EAC3_DECODER 0
|
||||
#define CONFIG_EVRC_DECODER 0
|
||||
#define CONFIG_FFWAVESYNTH_DECODER 0
|
||||
#define CONFIG_FLAC_DECODER 0
|
||||
#define CONFIG_FLAC_DECODER 1
|
||||
#define CONFIG_G723_1_DECODER 0
|
||||
#define CONFIG_G729_DECODER 0
|
||||
#define CONFIG_GSM_DECODER 0
|
||||
@ -2104,7 +2104,7 @@
|
||||
#define CONFIG_DVBSUB_PARSER 0
|
||||
#define CONFIG_DVDSUB_PARSER 0
|
||||
#define CONFIG_DVD_NAV_PARSER 0
|
||||
#define CONFIG_FLAC_PARSER 0
|
||||
#define CONFIG_FLAC_PARSER 1
|
||||
#define CONFIG_G729_PARSER 0
|
||||
#define CONFIG_GSM_PARSER 0
|
||||
#define CONFIG_H261_PARSER 0
|
||||
|
@ -575,11 +575,11 @@
|
||||
#define CONFIG_FAANDCT 0
|
||||
#define CONFIG_FAANIDCT 0
|
||||
#define CONFIG_FDCTDSP 0
|
||||
#define CONFIG_FLACDSP 0
|
||||
#define CONFIG_FLACDSP 1
|
||||
#define CONFIG_FMTCONVERT 0
|
||||
#define CONFIG_FRAME_THREAD_ENCODER 0
|
||||
#define CONFIG_G722DSP 0
|
||||
#define CONFIG_GOLOMB 0
|
||||
#define CONFIG_GOLOMB 1
|
||||
#define CONFIG_GPLV3 0
|
||||
#define CONFIG_H263DSP 0
|
||||
#define CONFIG_H264CHROMA 0
|
||||
@ -921,7 +921,7 @@
|
||||
#define CONFIG_EAC3_DECODER 0
|
||||
#define CONFIG_EVRC_DECODER 0
|
||||
#define CONFIG_FFWAVESYNTH_DECODER 0
|
||||
#define CONFIG_FLAC_DECODER 0
|
||||
#define CONFIG_FLAC_DECODER 1
|
||||
#define CONFIG_G723_1_DECODER 0
|
||||
#define CONFIG_G729_DECODER 0
|
||||
#define CONFIG_GSM_DECODER 0
|
||||
@ -2103,7 +2103,7 @@
|
||||
#define CONFIG_DVBSUB_PARSER 0
|
||||
#define CONFIG_DVDSUB_PARSER 0
|
||||
#define CONFIG_DVD_NAV_PARSER 0
|
||||
#define CONFIG_FLAC_PARSER 0
|
||||
#define CONFIG_FLAC_PARSER 1
|
||||
#define CONFIG_G729_PARSER 0
|
||||
#define CONFIG_GSM_PARSER 0
|
||||
#define CONFIG_H261_PARSER 0
|
||||
|
@ -561,11 +561,11 @@
|
||||
%define CONFIG_FAANDCT 0
|
||||
%define CONFIG_FAANIDCT 0
|
||||
%define CONFIG_FDCTDSP 0
|
||||
%define CONFIG_FLACDSP 0
|
||||
%define CONFIG_FLACDSP 1
|
||||
%define CONFIG_FMTCONVERT 0
|
||||
%define CONFIG_FRAME_THREAD_ENCODER 0
|
||||
%define CONFIG_G722DSP 0
|
||||
%define CONFIG_GOLOMB 0
|
||||
%define CONFIG_GOLOMB 1
|
||||
%define CONFIG_GPLV3 0
|
||||
%define CONFIG_H263DSP 0
|
||||
%define CONFIG_H264CHROMA 0
|
||||
@ -907,7 +907,7 @@
|
||||
%define CONFIG_EAC3_DECODER 0
|
||||
%define CONFIG_EVRC_DECODER 0
|
||||
%define CONFIG_FFWAVESYNTH_DECODER 0
|
||||
%define CONFIG_FLAC_DECODER 0
|
||||
%define CONFIG_FLAC_DECODER 1
|
||||
%define CONFIG_G723_1_DECODER 0
|
||||
%define CONFIG_G729_DECODER 0
|
||||
%define CONFIG_GSM_DECODER 0
|
||||
@ -2089,7 +2089,7 @@
|
||||
%define CONFIG_DVBSUB_PARSER 0
|
||||
%define CONFIG_DVDSUB_PARSER 0
|
||||
%define CONFIG_DVD_NAV_PARSER 0
|
||||
%define CONFIG_FLAC_PARSER 0
|
||||
%define CONFIG_FLAC_PARSER 1
|
||||
%define CONFIG_G729_PARSER 0
|
||||
%define CONFIG_GSM_PARSER 0
|
||||
%define CONFIG_H261_PARSER 0
|
||||
|
@ -576,11 +576,11 @@
|
||||
#define CONFIG_FAANDCT 0
|
||||
#define CONFIG_FAANIDCT 0
|
||||
#define CONFIG_FDCTDSP 0
|
||||
#define CONFIG_FLACDSP 0
|
||||
#define CONFIG_FLACDSP 1
|
||||
#define CONFIG_FMTCONVERT 0
|
||||
#define CONFIG_FRAME_THREAD_ENCODER 0
|
||||
#define CONFIG_G722DSP 0
|
||||
#define CONFIG_GOLOMB 0
|
||||
#define CONFIG_GOLOMB 1
|
||||
#define CONFIG_GPLV3 0
|
||||
#define CONFIG_H263DSP 0
|
||||
#define CONFIG_H264CHROMA 0
|
||||
@ -922,7 +922,7 @@
|
||||
#define CONFIG_EAC3_DECODER 0
|
||||
#define CONFIG_EVRC_DECODER 0
|
||||
#define CONFIG_FFWAVESYNTH_DECODER 0
|
||||
#define CONFIG_FLAC_DECODER 0
|
||||
#define CONFIG_FLAC_DECODER 1
|
||||
#define CONFIG_G723_1_DECODER 0
|
||||
#define CONFIG_G729_DECODER 0
|
||||
#define CONFIG_GSM_DECODER 0
|
||||
@ -2104,7 +2104,7 @@
|
||||
#define CONFIG_DVBSUB_PARSER 0
|
||||
#define CONFIG_DVDSUB_PARSER 0
|
||||
#define CONFIG_DVD_NAV_PARSER 0
|
||||
#define CONFIG_FLAC_PARSER 0
|
||||
#define CONFIG_FLAC_PARSER 1
|
||||
#define CONFIG_G729_PARSER 0
|
||||
#define CONFIG_GSM_PARSER 0
|
||||
#define CONFIG_H261_PARSER 0
|
||||
|
@ -561,11 +561,11 @@
|
||||
%define CONFIG_FAANDCT 0
|
||||
%define CONFIG_FAANIDCT 0
|
||||
%define CONFIG_FDCTDSP 0
|
||||
%define CONFIG_FLACDSP 0
|
||||
%define CONFIG_FLACDSP 1
|
||||
%define CONFIG_FMTCONVERT 0
|
||||
%define CONFIG_FRAME_THREAD_ENCODER 0
|
||||
%define CONFIG_G722DSP 0
|
||||
%define CONFIG_GOLOMB 0
|
||||
%define CONFIG_GOLOMB 1
|
||||
%define CONFIG_GPLV3 0
|
||||
%define CONFIG_H263DSP 0
|
||||
%define CONFIG_H264CHROMA 0
|
||||
@ -907,7 +907,7 @@
|
||||
%define CONFIG_EAC3_DECODER 0
|
||||
%define CONFIG_EVRC_DECODER 0
|
||||
%define CONFIG_FFWAVESYNTH_DECODER 0
|
||||
%define CONFIG_FLAC_DECODER 0
|
||||
%define CONFIG_FLAC_DECODER 1
|
||||
%define CONFIG_G723_1_DECODER 0
|
||||
%define CONFIG_G729_DECODER 0
|
||||
%define CONFIG_GSM_DECODER 0
|
||||
@ -2089,7 +2089,7 @@
|
||||
%define CONFIG_DVBSUB_PARSER 0
|
||||
%define CONFIG_DVDSUB_PARSER 0
|
||||
%define CONFIG_DVD_NAV_PARSER 0
|
||||
%define CONFIG_FLAC_PARSER 0
|
||||
%define CONFIG_FLAC_PARSER 1
|
||||
%define CONFIG_G729_PARSER 0
|
||||
%define CONFIG_GSM_PARSER 0
|
||||
%define CONFIG_H261_PARSER 0
|
||||
|
@ -576,11 +576,11 @@
|
||||
#define CONFIG_FAANDCT 0
|
||||
#define CONFIG_FAANIDCT 0
|
||||
#define CONFIG_FDCTDSP 0
|
||||
#define CONFIG_FLACDSP 0
|
||||
#define CONFIG_FLACDSP 1
|
||||
#define CONFIG_FMTCONVERT 0
|
||||
#define CONFIG_FRAME_THREAD_ENCODER 0
|
||||
#define CONFIG_G722DSP 0
|
||||
#define CONFIG_GOLOMB 0
|
||||
#define CONFIG_GOLOMB 1
|
||||
#define CONFIG_GPLV3 0
|
||||
#define CONFIG_H263DSP 0
|
||||
#define CONFIG_H264CHROMA 0
|
||||
@ -922,7 +922,7 @@
|
||||
#define CONFIG_EAC3_DECODER 0
|
||||
#define CONFIG_EVRC_DECODER 0
|
||||
#define CONFIG_FFWAVESYNTH_DECODER 0
|
||||
#define CONFIG_FLAC_DECODER 0
|
||||
#define CONFIG_FLAC_DECODER 1
|
||||
#define CONFIG_G723_1_DECODER 0
|
||||
#define CONFIG_G729_DECODER 0
|
||||
#define CONFIG_GSM_DECODER 0
|
||||
@ -2104,7 +2104,7 @@
|
||||
#define CONFIG_DVBSUB_PARSER 0
|
||||
#define CONFIG_DVDSUB_PARSER 0
|
||||
#define CONFIG_DVD_NAV_PARSER 0
|
||||
#define CONFIG_FLAC_PARSER 0
|
||||
#define CONFIG_FLAC_PARSER 1
|
||||
#define CONFIG_G729_PARSER 0
|
||||
#define CONFIG_GSM_PARSER 0
|
||||
#define CONFIG_H261_PARSER 0
|
||||
|
@ -561,11 +561,11 @@
|
||||
%define CONFIG_FAANDCT 0
|
||||
%define CONFIG_FAANIDCT 0
|
||||
%define CONFIG_FDCTDSP 0
|
||||
%define CONFIG_FLACDSP 0
|
||||
%define CONFIG_FLACDSP 1
|
||||
%define CONFIG_FMTCONVERT 0
|
||||
%define CONFIG_FRAME_THREAD_ENCODER 0
|
||||
%define CONFIG_G722DSP 0
|
||||
%define CONFIG_GOLOMB 0
|
||||
%define CONFIG_GOLOMB 1
|
||||
%define CONFIG_GPLV3 0
|
||||
%define CONFIG_H263DSP 0
|
||||
%define CONFIG_H264CHROMA 0
|
||||
@ -907,7 +907,7 @@
|
||||
%define CONFIG_EAC3_DECODER 0
|
||||
%define CONFIG_EVRC_DECODER 0
|
||||
%define CONFIG_FFWAVESYNTH_DECODER 0
|
||||
%define CONFIG_FLAC_DECODER 0
|
||||
%define CONFIG_FLAC_DECODER 1
|
||||
%define CONFIG_G723_1_DECODER 0
|
||||
%define CONFIG_G729_DECODER 0
|
||||
%define CONFIG_GSM_DECODER 0
|
||||
@ -2089,7 +2089,7 @@
|
||||
%define CONFIG_DVBSUB_PARSER 0
|
||||
%define CONFIG_DVDSUB_PARSER 0
|
||||
%define CONFIG_DVD_NAV_PARSER 0
|
||||
%define CONFIG_FLAC_PARSER 0
|
||||
%define CONFIG_FLAC_PARSER 1
|
||||
%define CONFIG_G729_PARSER 0
|
||||
%define CONFIG_GSM_PARSER 0
|
||||
%define CONFIG_H261_PARSER 0
|
||||
|
@ -576,11 +576,11 @@
|
||||
#define CONFIG_FAANDCT 0
|
||||
#define CONFIG_FAANIDCT 0
|
||||
#define CONFIG_FDCTDSP 0
|
||||
#define CONFIG_FLACDSP 0
|
||||
#define CONFIG_FLACDSP 1
|
||||
#define CONFIG_FMTCONVERT 0
|
||||
#define CONFIG_FRAME_THREAD_ENCODER 0
|
||||
#define CONFIG_G722DSP 0
|
||||
#define CONFIG_GOLOMB 0
|
||||
#define CONFIG_GOLOMB 1
|
||||
#define CONFIG_GPLV3 0
|
||||
#define CONFIG_H263DSP 0
|
||||
#define CONFIG_H264CHROMA 0
|
||||
@ -922,7 +922,7 @@
|
||||
#define CONFIG_EAC3_DECODER 0
|
||||
#define CONFIG_EVRC_DECODER 0
|
||||
#define CONFIG_FFWAVESYNTH_DECODER 0
|
||||
#define CONFIG_FLAC_DECODER 0
|
||||
#define CONFIG_FLAC_DECODER 1
|
||||
#define CONFIG_G723_1_DECODER 0
|
||||
#define CONFIG_G729_DECODER 0
|
||||
#define CONFIG_GSM_DECODER 0
|
||||
@ -2104,7 +2104,7 @@
|
||||
#define CONFIG_DVBSUB_PARSER 0
|
||||
#define CONFIG_DVDSUB_PARSER 0
|
||||
#define CONFIG_DVD_NAV_PARSER 0
|
||||
#define CONFIG_FLAC_PARSER 0
|
||||
#define CONFIG_FLAC_PARSER 1
|
||||
#define CONFIG_G729_PARSER 0
|
||||
#define CONFIG_GSM_PARSER 0
|
||||
#define CONFIG_H261_PARSER 0
|
||||
|
@ -10,6 +10,7 @@ typedef struct H264PredContext H264PredContext;
|
||||
typedef struct VideoDSPContext VideoDSPContext;
|
||||
typedef struct VP8DSPContext VP8DSPContext;
|
||||
typedef struct VP9DSPContext VP9DSPContext;
|
||||
typedef struct FLACDSPContext FLACDSPContext;
|
||||
|
||||
AVHWAccel ff_h263_vaapi_hwaccel;
|
||||
AVHWAccel ff_h263_vdpau_hwaccel;
|
||||
@ -400,7 +401,6 @@ AVCodec ff_eac3_decoder;
|
||||
AVCodec ff_evrc_decoder;
|
||||
AVCodec ff_ffwavesynth_decoder;
|
||||
AVCodec ff_flac_encoder;
|
||||
AVCodec ff_flac_decoder;
|
||||
AVCodec ff_g723_1_encoder;
|
||||
AVCodec ff_g723_1_decoder;
|
||||
AVCodec ff_g729_decoder;
|
||||
@ -729,7 +729,6 @@ AVCodecParser ff_dvaudio_parser;
|
||||
AVCodecParser ff_dvbsub_parser;
|
||||
AVCodecParser ff_dvdsub_parser;
|
||||
AVCodecParser ff_dvd_nav_parser;
|
||||
AVCodecParser ff_flac_parser;
|
||||
AVCodecParser ff_g729_parser;
|
||||
AVCodecParser ff_gsm_parser;
|
||||
AVCodecParser ff_h261_parser;
|
||||
@ -785,7 +784,13 @@ void ff_vp78dsp_init_ppc(VP8DSPContext *c) {}
|
||||
void ff_vp8dsp_init_arm(VP8DSPContext *c) {}
|
||||
void ff_vp8dsp_init_mips(VP8DSPContext *c) {}
|
||||
void ff_vp9dsp_init_mips(VP9DSPContext *dsp, int bpp) {}
|
||||
|
||||
void ff_flacdsp_init_arm(FLACDSPContext *c, enum AVSampleFormat fmt, int channels, int bps) {}
|
||||
#if !defined(HAVE_64BIT_BUILD)
|
||||
void ff_flac_decorrelate_indep8_16_sse2(uint8_t **out, int32_t **in, int channels, int len, int shift) {}
|
||||
void ff_flac_decorrelate_indep8_32_avx(uint8_t **out, int32_t **in, int channels, int len, int shift) {}
|
||||
void ff_flac_decorrelate_indep8_16_avx(uint8_t **out, int32_t **in, int channels, int len, int shift) {}
|
||||
void ff_flac_decorrelate_indep8_32_sse2(uint8_t **out, int32_t **in, int channels, int len, int shift) {}
|
||||
#endif
|
||||
void av_bitstream_filter_close(AVBitStreamFilterContext *bsf) {}
|
||||
int av_bitstream_filter_filter(AVBitStreamFilterContext *bsfc,
|
||||
AVCodecContext *avctx, const char *args,
|
||||
|
237
media/ffvpx/libavcodec/flac.c
Normal file
237
media/ffvpx/libavcodec/flac.c
Normal file
@ -0,0 +1,237 @@
|
||||
/*
|
||||
* FLAC common code
|
||||
* Copyright (c) 2009 Justin Ruggles
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "libavutil/channel_layout.h"
|
||||
#include "libavutil/crc.h"
|
||||
#include "libavutil/log.h"
|
||||
#include "bytestream.h"
|
||||
#include "get_bits.h"
|
||||
#include "flac.h"
|
||||
#include "flacdata.h"
|
||||
|
||||
static const int8_t sample_size_table[] = { 0, 8, 12, 0, 16, 20, 24, 0 };
|
||||
|
||||
static const uint64_t flac_channel_layouts[8] = {
|
||||
AV_CH_LAYOUT_MONO,
|
||||
AV_CH_LAYOUT_STEREO,
|
||||
AV_CH_LAYOUT_SURROUND,
|
||||
AV_CH_LAYOUT_QUAD,
|
||||
AV_CH_LAYOUT_5POINT0,
|
||||
AV_CH_LAYOUT_5POINT1,
|
||||
AV_CH_LAYOUT_6POINT1,
|
||||
AV_CH_LAYOUT_7POINT1
|
||||
};
|
||||
|
||||
static int64_t get_utf8(GetBitContext *gb)
|
||||
{
|
||||
int64_t val;
|
||||
GET_UTF8(val, get_bits(gb, 8), return -1;)
|
||||
return val;
|
||||
}
|
||||
|
||||
int ff_flac_decode_frame_header(AVCodecContext *avctx, GetBitContext *gb,
|
||||
FLACFrameInfo *fi, int log_level_offset)
|
||||
{
|
||||
int bs_code, sr_code, bps_code;
|
||||
|
||||
/* frame sync code */
|
||||
if ((get_bits(gb, 15) & 0x7FFF) != 0x7FFC) {
|
||||
av_log(avctx, AV_LOG_ERROR + log_level_offset, "invalid sync code\n");
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
/* variable block size stream code */
|
||||
fi->is_var_size = get_bits1(gb);
|
||||
|
||||
/* block size and sample rate codes */
|
||||
bs_code = get_bits(gb, 4);
|
||||
sr_code = get_bits(gb, 4);
|
||||
|
||||
/* channels and decorrelation */
|
||||
fi->ch_mode = get_bits(gb, 4);
|
||||
if (fi->ch_mode < FLAC_MAX_CHANNELS) {
|
||||
fi->channels = fi->ch_mode + 1;
|
||||
fi->ch_mode = FLAC_CHMODE_INDEPENDENT;
|
||||
} else if (fi->ch_mode < FLAC_MAX_CHANNELS + FLAC_CHMODE_MID_SIDE) {
|
||||
fi->channels = 2;
|
||||
fi->ch_mode -= FLAC_MAX_CHANNELS - 1;
|
||||
} else {
|
||||
av_log(avctx, AV_LOG_ERROR + log_level_offset,
|
||||
"invalid channel mode: %d\n", fi->ch_mode);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
/* bits per sample */
|
||||
bps_code = get_bits(gb, 3);
|
||||
if (bps_code == 3 || bps_code == 7) {
|
||||
av_log(avctx, AV_LOG_ERROR + log_level_offset,
|
||||
"invalid sample size code (%d)\n",
|
||||
bps_code);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
fi->bps = sample_size_table[bps_code];
|
||||
|
||||
/* reserved bit */
|
||||
if (get_bits1(gb)) {
|
||||
av_log(avctx, AV_LOG_ERROR + log_level_offset,
|
||||
"broken stream, invalid padding\n");
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
/* sample or frame count */
|
||||
fi->frame_or_sample_num = get_utf8(gb);
|
||||
if (fi->frame_or_sample_num < 0) {
|
||||
av_log(avctx, AV_LOG_ERROR + log_level_offset,
|
||||
"sample/frame number invalid; utf8 fscked\n");
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
/* blocksize */
|
||||
if (bs_code == 0) {
|
||||
av_log(avctx, AV_LOG_ERROR + log_level_offset,
|
||||
"reserved blocksize code: 0\n");
|
||||
return AVERROR_INVALIDDATA;
|
||||
} else if (bs_code == 6) {
|
||||
fi->blocksize = get_bits(gb, 8) + 1;
|
||||
} else if (bs_code == 7) {
|
||||
fi->blocksize = get_bits(gb, 16) + 1;
|
||||
} else {
|
||||
fi->blocksize = ff_flac_blocksize_table[bs_code];
|
||||
}
|
||||
|
||||
/* sample rate */
|
||||
if (sr_code < 12) {
|
||||
fi->samplerate = ff_flac_sample_rate_table[sr_code];
|
||||
} else if (sr_code == 12) {
|
||||
fi->samplerate = get_bits(gb, 8) * 1000;
|
||||
} else if (sr_code == 13) {
|
||||
fi->samplerate = get_bits(gb, 16);
|
||||
} else if (sr_code == 14) {
|
||||
fi->samplerate = get_bits(gb, 16) * 10;
|
||||
} else {
|
||||
av_log(avctx, AV_LOG_ERROR + log_level_offset,
|
||||
"illegal sample rate code %d\n",
|
||||
sr_code);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
/* header CRC-8 check */
|
||||
skip_bits(gb, 8);
|
||||
if (av_crc(av_crc_get_table(AV_CRC_8_ATM), 0, gb->buffer,
|
||||
get_bits_count(gb)/8)) {
|
||||
av_log(avctx, AV_LOG_ERROR + log_level_offset,
|
||||
"header crc mismatch\n");
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ff_flac_get_max_frame_size(int blocksize, int ch, int bps)
|
||||
{
|
||||
/* Technically, there is no limit to FLAC frame size, but an encoder
|
||||
should not write a frame that is larger than if verbatim encoding mode
|
||||
were to be used. */
|
||||
|
||||
int count;
|
||||
|
||||
count = 16; /* frame header */
|
||||
count += ch * ((7+bps+7)/8); /* subframe headers */
|
||||
if (ch == 2) {
|
||||
/* for stereo, need to account for using decorrelation */
|
||||
count += (( 2*bps+1) * blocksize + 7) / 8;
|
||||
} else {
|
||||
count += ( ch*bps * blocksize + 7) / 8;
|
||||
}
|
||||
count += 2; /* frame footer */
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int ff_flac_is_extradata_valid(AVCodecContext *avctx,
|
||||
enum FLACExtradataFormat *format,
|
||||
uint8_t **streaminfo_start)
|
||||
{
|
||||
if (!avctx->extradata || avctx->extradata_size < FLAC_STREAMINFO_SIZE) {
|
||||
av_log(avctx, AV_LOG_ERROR, "extradata NULL or too small.\n");
|
||||
return 0;
|
||||
}
|
||||
if (AV_RL32(avctx->extradata) != MKTAG('f','L','a','C')) {
|
||||
/* extradata contains STREAMINFO only */
|
||||
if (avctx->extradata_size != FLAC_STREAMINFO_SIZE) {
|
||||
av_log(avctx, AV_LOG_WARNING, "extradata contains %d bytes too many.\n",
|
||||
FLAC_STREAMINFO_SIZE-avctx->extradata_size);
|
||||
}
|
||||
*format = FLAC_EXTRADATA_FORMAT_STREAMINFO;
|
||||
*streaminfo_start = avctx->extradata;
|
||||
} else {
|
||||
if (avctx->extradata_size < 8+FLAC_STREAMINFO_SIZE) {
|
||||
av_log(avctx, AV_LOG_ERROR, "extradata too small.\n");
|
||||
return 0;
|
||||
}
|
||||
*format = FLAC_EXTRADATA_FORMAT_FULL_HEADER;
|
||||
*streaminfo_start = &avctx->extradata[8];
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ff_flac_set_channel_layout(AVCodecContext *avctx)
|
||||
{
|
||||
if (avctx->channels <= FF_ARRAY_ELEMS(flac_channel_layouts))
|
||||
avctx->channel_layout = flac_channel_layouts[avctx->channels - 1];
|
||||
else
|
||||
avctx->channel_layout = 0;
|
||||
}
|
||||
|
||||
void ff_flac_parse_streaminfo(AVCodecContext *avctx, struct FLACStreaminfo *s,
|
||||
const uint8_t *buffer)
|
||||
{
|
||||
GetBitContext gb;
|
||||
init_get_bits(&gb, buffer, FLAC_STREAMINFO_SIZE*8);
|
||||
|
||||
skip_bits(&gb, 16); /* skip min blocksize */
|
||||
s->max_blocksize = get_bits(&gb, 16);
|
||||
if (s->max_blocksize < FLAC_MIN_BLOCKSIZE) {
|
||||
av_log(avctx, AV_LOG_WARNING, "invalid max blocksize: %d\n",
|
||||
s->max_blocksize);
|
||||
s->max_blocksize = 16;
|
||||
}
|
||||
|
||||
skip_bits(&gb, 24); /* skip min frame size */
|
||||
s->max_framesize = get_bits_long(&gb, 24);
|
||||
|
||||
s->samplerate = get_bits_long(&gb, 20);
|
||||
s->channels = get_bits(&gb, 3) + 1;
|
||||
s->bps = get_bits(&gb, 5) + 1;
|
||||
|
||||
avctx->channels = s->channels;
|
||||
avctx->sample_rate = s->samplerate;
|
||||
avctx->bits_per_raw_sample = s->bps;
|
||||
|
||||
if (!avctx->channel_layout ||
|
||||
av_get_channel_layout_nb_channels(avctx->channel_layout) != avctx->channels)
|
||||
ff_flac_set_channel_layout(avctx);
|
||||
|
||||
s->samples = get_bits64(&gb, 36);
|
||||
|
||||
skip_bits_long(&gb, 64); /* md5 sum */
|
||||
skip_bits_long(&gb, 64); /* md5 sum */
|
||||
}
|
153
media/ffvpx/libavcodec/flac.h
Normal file
153
media/ffvpx/libavcodec/flac.h
Normal file
@ -0,0 +1,153 @@
|
||||
/*
|
||||
* FLAC (Free Lossless Audio Codec) decoder/demuxer common functions
|
||||
* Copyright (c) 2008 Justin Ruggles
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* FLAC (Free Lossless Audio Codec) decoder/demuxer common functions
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_FLAC_H
|
||||
#define AVCODEC_FLAC_H
|
||||
|
||||
#include "avcodec.h"
|
||||
#include "bytestream.h"
|
||||
#include "get_bits.h"
|
||||
|
||||
#define FLAC_STREAMINFO_SIZE 34
|
||||
#define FLAC_MAX_CHANNELS 8
|
||||
#define FLAC_MIN_BLOCKSIZE 16
|
||||
#define FLAC_MAX_BLOCKSIZE 65535
|
||||
#define FLAC_MIN_FRAME_SIZE 11
|
||||
|
||||
enum {
|
||||
FLAC_CHMODE_INDEPENDENT = 0,
|
||||
FLAC_CHMODE_LEFT_SIDE = 1,
|
||||
FLAC_CHMODE_RIGHT_SIDE = 2,
|
||||
FLAC_CHMODE_MID_SIDE = 3,
|
||||
};
|
||||
|
||||
enum {
|
||||
FLAC_METADATA_TYPE_STREAMINFO = 0,
|
||||
FLAC_METADATA_TYPE_PADDING,
|
||||
FLAC_METADATA_TYPE_APPLICATION,
|
||||
FLAC_METADATA_TYPE_SEEKTABLE,
|
||||
FLAC_METADATA_TYPE_VORBIS_COMMENT,
|
||||
FLAC_METADATA_TYPE_CUESHEET,
|
||||
FLAC_METADATA_TYPE_PICTURE,
|
||||
FLAC_METADATA_TYPE_INVALID = 127
|
||||
};
|
||||
|
||||
enum FLACExtradataFormat {
|
||||
FLAC_EXTRADATA_FORMAT_STREAMINFO = 0,
|
||||
FLAC_EXTRADATA_FORMAT_FULL_HEADER = 1
|
||||
};
|
||||
|
||||
#define FLACCOMMONINFO \
|
||||
int samplerate; /**< sample rate */\
|
||||
int channels; /**< number of channels */\
|
||||
int bps; /**< bits-per-sample */\
|
||||
|
||||
/**
|
||||
* Data needed from the Streaminfo header for use by the raw FLAC demuxer
|
||||
* and/or the FLAC decoder.
|
||||
*/
|
||||
#define FLACSTREAMINFO \
|
||||
FLACCOMMONINFO \
|
||||
int max_blocksize; /**< maximum block size, in samples */\
|
||||
int max_framesize; /**< maximum frame size, in bytes */\
|
||||
int64_t samples; /**< total number of samples */\
|
||||
|
||||
typedef struct FLACStreaminfo {
|
||||
FLACSTREAMINFO
|
||||
} FLACStreaminfo;
|
||||
|
||||
typedef struct FLACFrameInfo {
|
||||
FLACCOMMONINFO
|
||||
int blocksize; /**< block size of the frame */
|
||||
int ch_mode; /**< channel decorrelation mode */
|
||||
int64_t frame_or_sample_num; /**< frame number or sample number */
|
||||
int is_var_size; /**< specifies if the stream uses variable
|
||||
block sizes or a fixed block size;
|
||||
also determines the meaning of
|
||||
frame_or_sample_num */
|
||||
} FLACFrameInfo;
|
||||
|
||||
/**
|
||||
* Parse the Streaminfo metadata block
|
||||
* @param[out] avctx codec context to set basic stream parameters
|
||||
* @param[out] s where parsed information is stored
|
||||
* @param[in] buffer pointer to start of 34-byte streaminfo data
|
||||
*/
|
||||
void ff_flac_parse_streaminfo(AVCodecContext *avctx, struct FLACStreaminfo *s,
|
||||
const uint8_t *buffer);
|
||||
|
||||
/**
|
||||
* Validate the FLAC extradata.
|
||||
* @param[in] avctx codec context containing the extradata.
|
||||
* @param[out] format extradata format.
|
||||
* @param[out] streaminfo_start pointer to start of 34-byte STREAMINFO data.
|
||||
* @return 1 if valid, 0 if not valid.
|
||||
*/
|
||||
int ff_flac_is_extradata_valid(AVCodecContext *avctx,
|
||||
enum FLACExtradataFormat *format,
|
||||
uint8_t **streaminfo_start);
|
||||
|
||||
/**
|
||||
* Calculate an estimate for the maximum frame size based on verbatim mode.
|
||||
* @param blocksize block size, in samples
|
||||
* @param ch number of channels
|
||||
* @param bps bits-per-sample
|
||||
*/
|
||||
int ff_flac_get_max_frame_size(int blocksize, int ch, int bps);
|
||||
|
||||
/**
|
||||
* Validate and decode a frame header.
|
||||
* @param avctx AVCodecContext to use as av_log() context
|
||||
* @param gb GetBitContext from which to read frame header
|
||||
* @param[out] fi frame information
|
||||
* @param log_level_offset log level offset. can be used to silence error messages.
|
||||
* @return non-zero on error, 0 if ok
|
||||
*/
|
||||
int ff_flac_decode_frame_header(AVCodecContext *avctx, GetBitContext *gb,
|
||||
FLACFrameInfo *fi, int log_level_offset);
|
||||
|
||||
void ff_flac_set_channel_layout(AVCodecContext *avctx);
|
||||
|
||||
/**
|
||||
* Parse the metadata block parameters from the header.
|
||||
* @param[in] block_header header data, at least 4 bytes
|
||||
* @param[out] last indicator for last metadata block
|
||||
* @param[out] type metadata block type
|
||||
* @param[out] size metadata block size
|
||||
*/
|
||||
static av_always_inline void flac_parse_block_header(const uint8_t *block_header,
|
||||
int *last, int *type, int *size)
|
||||
{
|
||||
int tmp = bytestream_get_byte(&block_header);
|
||||
if (last)
|
||||
*last = tmp & 0x80;
|
||||
if (type)
|
||||
*type = tmp & 0x7F;
|
||||
if (size)
|
||||
*size = bytestream_get_be24(&block_header);
|
||||
}
|
||||
|
||||
#endif /* AVCODEC_FLAC_H */
|
755
media/ffvpx/libavcodec/flac_parser.c
Normal file
755
media/ffvpx/libavcodec/flac_parser.c
Normal file
@ -0,0 +1,755 @@
|
||||
/*
|
||||
* FLAC parser
|
||||
* Copyright (c) 2010 Michael Chinen
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* FLAC parser
|
||||
*
|
||||
* The FLAC parser buffers input until FLAC_MIN_HEADERS has been found.
|
||||
* Each time it finds and verifies a CRC-8 header it sees which of the
|
||||
* FLAC_MAX_SEQUENTIAL_HEADERS that came before it have a valid CRC-16 footer
|
||||
* that ends at the newly found header.
|
||||
* Headers are scored by FLAC_HEADER_BASE_SCORE plus the max of its crc-verified
|
||||
* children, penalized by changes in sample rate, frame number, etc.
|
||||
* The parser returns the frame with the highest score.
|
||||
**/
|
||||
|
||||
#include "libavutil/attributes.h"
|
||||
#include "libavutil/crc.h"
|
||||
#include "libavutil/fifo.h"
|
||||
#include "bytestream.h"
|
||||
#include "parser.h"
|
||||
#include "flac.h"
|
||||
|
||||
/** maximum number of adjacent headers that compare CRCs against each other */
|
||||
#define FLAC_MAX_SEQUENTIAL_HEADERS 4
|
||||
/** minimum number of headers buffered and checked before returning frames */
|
||||
#define FLAC_MIN_HEADERS 10
|
||||
/** estimate for average size of a FLAC frame */
|
||||
#define FLAC_AVG_FRAME_SIZE 8192
|
||||
|
||||
/** scoring settings for score_header */
|
||||
#define FLAC_HEADER_BASE_SCORE 10
|
||||
#define FLAC_HEADER_CHANGED_PENALTY 7
|
||||
#define FLAC_HEADER_CRC_FAIL_PENALTY 50
|
||||
#define FLAC_HEADER_NOT_PENALIZED_YET 100000
|
||||
#define FLAC_HEADER_NOT_SCORED_YET -100000
|
||||
|
||||
/** largest possible size of flac header */
|
||||
#define MAX_FRAME_HEADER_SIZE 16
|
||||
|
||||
typedef struct FLACHeaderMarker {
|
||||
int offset; /**< byte offset from start of FLACParseContext->buffer */
|
||||
int *link_penalty; /**< pointer to array of local scores between this header
|
||||
and the one at a distance equal array position */
|
||||
int max_score; /**< maximum score found after checking each child that
|
||||
has a valid CRC */
|
||||
FLACFrameInfo fi; /**< decoded frame header info */
|
||||
struct FLACHeaderMarker *next; /**< next CRC-8 verified header that
|
||||
immediately follows this one in
|
||||
the bytestream */
|
||||
struct FLACHeaderMarker *best_child; /**< following frame header with
|
||||
which this frame has the best
|
||||
score with */
|
||||
} FLACHeaderMarker;
|
||||
|
||||
typedef struct FLACParseContext {
|
||||
AVCodecParserContext *pc; /**< parent context */
|
||||
AVCodecContext *avctx; /**< codec context pointer for logging */
|
||||
FLACHeaderMarker *headers; /**< linked-list that starts at the first
|
||||
CRC-8 verified header within buffer */
|
||||
FLACHeaderMarker *best_header; /**< highest scoring header within buffer */
|
||||
int nb_headers_found; /**< number of headers found in the last
|
||||
flac_parse() call */
|
||||
int nb_headers_buffered; /**< number of headers that are buffered */
|
||||
int best_header_valid; /**< flag set when the parser returns junk;
|
||||
if set return best_header next time */
|
||||
AVFifoBuffer *fifo_buf; /**< buffer to store all data until headers
|
||||
can be verified */
|
||||
int end_padded; /**< specifies if fifo_buf's end is padded */
|
||||
uint8_t *wrap_buf; /**< general fifo read buffer when wrapped */
|
||||
int wrap_buf_allocated_size; /**< actual allocated size of the buffer */
|
||||
FLACFrameInfo last_fi; /**< last decoded frame header info */
|
||||
int last_fi_valid; /**< set if last_fi is valid */
|
||||
} FLACParseContext;
|
||||
|
||||
static int frame_header_is_valid(AVCodecContext *avctx, const uint8_t *buf,
|
||||
FLACFrameInfo *fi)
|
||||
{
|
||||
GetBitContext gb;
|
||||
init_get_bits(&gb, buf, MAX_FRAME_HEADER_SIZE * 8);
|
||||
return !ff_flac_decode_frame_header(avctx, &gb, fi, 127);
|
||||
}
|
||||
|
||||
/**
|
||||
* Non-destructive fast fifo pointer fetching
|
||||
* Returns a pointer from the specified offset.
|
||||
* If possible the pointer points within the fifo buffer.
|
||||
* Otherwise (if it would cause a wrap around,) a pointer to a user-specified
|
||||
* buffer is used.
|
||||
* The pointer can be NULL. In any case it will be reallocated to hold the size.
|
||||
* If the returned pointer will be used after subsequent calls to flac_fifo_read_wrap
|
||||
* then the subsequent calls should pass in a different wrap_buf so as to not
|
||||
* overwrite the contents of the previous wrap_buf.
|
||||
* This function is based on av_fifo_generic_read, which is why there is a comment
|
||||
* about a memory barrier for SMP.
|
||||
*/
|
||||
static uint8_t* flac_fifo_read_wrap(FLACParseContext *fpc, int offset, int len,
|
||||
uint8_t** wrap_buf, int* allocated_size)
|
||||
{
|
||||
AVFifoBuffer *f = fpc->fifo_buf;
|
||||
uint8_t *start = f->rptr + offset;
|
||||
uint8_t *tmp_buf;
|
||||
|
||||
if (start >= f->end)
|
||||
start -= f->end - f->buffer;
|
||||
if (f->end - start >= len)
|
||||
return start;
|
||||
|
||||
tmp_buf = av_fast_realloc(*wrap_buf, allocated_size, len);
|
||||
|
||||
if (!tmp_buf) {
|
||||
av_log(fpc->avctx, AV_LOG_ERROR,
|
||||
"couldn't reallocate wrap buffer of size %d", len);
|
||||
return NULL;
|
||||
}
|
||||
*wrap_buf = tmp_buf;
|
||||
do {
|
||||
int seg_len = FFMIN(f->end - start, len);
|
||||
memcpy(tmp_buf, start, seg_len);
|
||||
tmp_buf = (uint8_t*)tmp_buf + seg_len;
|
||||
// memory barrier needed for SMP here in theory
|
||||
|
||||
start += seg_len - (f->end - f->buffer);
|
||||
len -= seg_len;
|
||||
} while (len > 0);
|
||||
|
||||
return *wrap_buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a pointer in the fifo buffer where the offset starts at until
|
||||
* the wrap point or end of request.
|
||||
* len will contain the valid length of the returned buffer.
|
||||
* A second call to flac_fifo_read (with new offset and len) should be called
|
||||
* to get the post-wrap buf if the returned len is less than the requested.
|
||||
**/
|
||||
static uint8_t* flac_fifo_read(FLACParseContext *fpc, int offset, int *len)
|
||||
{
|
||||
AVFifoBuffer *f = fpc->fifo_buf;
|
||||
uint8_t *start = f->rptr + offset;
|
||||
|
||||
if (start >= f->end)
|
||||
start -= f->end - f->buffer;
|
||||
*len = FFMIN(*len, f->end - start);
|
||||
return start;
|
||||
}
|
||||
|
||||
static int find_headers_search_validate(FLACParseContext *fpc, int offset)
|
||||
{
|
||||
FLACFrameInfo fi;
|
||||
uint8_t *header_buf;
|
||||
int size = 0;
|
||||
header_buf = flac_fifo_read_wrap(fpc, offset,
|
||||
MAX_FRAME_HEADER_SIZE,
|
||||
&fpc->wrap_buf,
|
||||
&fpc->wrap_buf_allocated_size);
|
||||
if (frame_header_is_valid(fpc->avctx, header_buf, &fi)) {
|
||||
FLACHeaderMarker **end_handle = &fpc->headers;
|
||||
int i;
|
||||
|
||||
size = 0;
|
||||
while (*end_handle) {
|
||||
end_handle = &(*end_handle)->next;
|
||||
size++;
|
||||
}
|
||||
|
||||
*end_handle = av_mallocz(sizeof(**end_handle));
|
||||
if (!*end_handle) {
|
||||
av_log(fpc->avctx, AV_LOG_ERROR,
|
||||
"couldn't allocate FLACHeaderMarker\n");
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
(*end_handle)->fi = fi;
|
||||
(*end_handle)->offset = offset;
|
||||
(*end_handle)->link_penalty = av_malloc(sizeof(int) *
|
||||
FLAC_MAX_SEQUENTIAL_HEADERS);
|
||||
if (!(*end_handle)->link_penalty) {
|
||||
av_freep(end_handle);
|
||||
av_log(fpc->avctx, AV_LOG_ERROR,
|
||||
"couldn't allocate link_penalty\n");
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
|
||||
for (i = 0; i < FLAC_MAX_SEQUENTIAL_HEADERS; i++)
|
||||
(*end_handle)->link_penalty[i] = FLAC_HEADER_NOT_PENALIZED_YET;
|
||||
|
||||
fpc->nb_headers_found++;
|
||||
size++;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
static int find_headers_search(FLACParseContext *fpc, uint8_t *buf, int buf_size,
|
||||
int search_start)
|
||||
|
||||
{
|
||||
int size = 0, mod_offset = (buf_size - 1) % 4, i, j;
|
||||
uint32_t x;
|
||||
|
||||
for (i = 0; i < mod_offset; i++) {
|
||||
if ((AV_RB16(buf + i) & 0xFFFE) == 0xFFF8)
|
||||
size = find_headers_search_validate(fpc, search_start + i);
|
||||
}
|
||||
|
||||
for (; i < buf_size - 1; i += 4) {
|
||||
x = AV_RB32(buf + i);
|
||||
if (((x & ~(x + 0x01010101)) & 0x80808080)) {
|
||||
for (j = 0; j < 4; j++) {
|
||||
if ((AV_RB16(buf + i + j) & 0xFFFE) == 0xFFF8)
|
||||
size = find_headers_search_validate(fpc, search_start + i + j);
|
||||
}
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
static int find_new_headers(FLACParseContext *fpc, int search_start)
|
||||
{
|
||||
FLACHeaderMarker *end;
|
||||
int search_end, size = 0, read_len, temp;
|
||||
uint8_t *buf;
|
||||
fpc->nb_headers_found = 0;
|
||||
|
||||
/* Search for a new header of at most 16 bytes. */
|
||||
search_end = av_fifo_size(fpc->fifo_buf) - (MAX_FRAME_HEADER_SIZE - 1);
|
||||
read_len = search_end - search_start + 1;
|
||||
buf = flac_fifo_read(fpc, search_start, &read_len);
|
||||
size = find_headers_search(fpc, buf, read_len, search_start);
|
||||
search_start += read_len - 1;
|
||||
|
||||
/* If fifo end was hit do the wrap around. */
|
||||
if (search_start != search_end) {
|
||||
uint8_t wrap[2];
|
||||
|
||||
wrap[0] = buf[read_len - 1];
|
||||
read_len = search_end - search_start + 1;
|
||||
|
||||
/* search_start + 1 is the post-wrap offset in the fifo. */
|
||||
buf = flac_fifo_read(fpc, search_start + 1, &read_len);
|
||||
wrap[1] = buf[0];
|
||||
|
||||
if ((AV_RB16(wrap) & 0xFFFE) == 0xFFF8) {
|
||||
temp = find_headers_search_validate(fpc, search_start);
|
||||
size = FFMAX(size, temp);
|
||||
}
|
||||
search_start++;
|
||||
|
||||
/* Continue to do the last half of the wrap. */
|
||||
temp = find_headers_search(fpc, buf, read_len, search_start);
|
||||
size = FFMAX(size, temp);
|
||||
search_start += read_len - 1;
|
||||
}
|
||||
|
||||
/* Return the size even if no new headers were found. */
|
||||
if (!size && fpc->headers)
|
||||
for (end = fpc->headers; end; end = end->next)
|
||||
size++;
|
||||
return size;
|
||||
}
|
||||
|
||||
static int check_header_fi_mismatch(FLACParseContext *fpc,
|
||||
FLACFrameInfo *header_fi,
|
||||
FLACFrameInfo *child_fi,
|
||||
int log_level_offset)
|
||||
{
|
||||
int deduction = 0;
|
||||
if (child_fi->samplerate != header_fi->samplerate) {
|
||||
deduction += FLAC_HEADER_CHANGED_PENALTY;
|
||||
av_log(fpc->avctx, AV_LOG_WARNING + log_level_offset,
|
||||
"sample rate change detected in adjacent frames\n");
|
||||
}
|
||||
if (child_fi->bps != header_fi->bps) {
|
||||
deduction += FLAC_HEADER_CHANGED_PENALTY;
|
||||
av_log(fpc->avctx, AV_LOG_WARNING + log_level_offset,
|
||||
"bits per sample change detected in adjacent frames\n");
|
||||
}
|
||||
if (child_fi->is_var_size != header_fi->is_var_size) {
|
||||
/* Changing blocking strategy not allowed per the spec */
|
||||
deduction += FLAC_HEADER_BASE_SCORE;
|
||||
av_log(fpc->avctx, AV_LOG_WARNING + log_level_offset,
|
||||
"blocking strategy change detected in adjacent frames\n");
|
||||
}
|
||||
if (child_fi->channels != header_fi->channels) {
|
||||
deduction += FLAC_HEADER_CHANGED_PENALTY;
|
||||
av_log(fpc->avctx, AV_LOG_WARNING + log_level_offset,
|
||||
"number of channels change detected in adjacent frames\n");
|
||||
}
|
||||
return deduction;
|
||||
}
|
||||
|
||||
static int check_header_mismatch(FLACParseContext *fpc,
|
||||
FLACHeaderMarker *header,
|
||||
FLACHeaderMarker *child,
|
||||
int log_level_offset)
|
||||
{
|
||||
FLACFrameInfo *header_fi = &header->fi, *child_fi = &child->fi;
|
||||
int deduction, deduction_expected = 0, i;
|
||||
deduction = check_header_fi_mismatch(fpc, header_fi, child_fi,
|
||||
log_level_offset);
|
||||
/* Check sample and frame numbers. */
|
||||
if ((child_fi->frame_or_sample_num - header_fi->frame_or_sample_num
|
||||
!= header_fi->blocksize) &&
|
||||
(child_fi->frame_or_sample_num
|
||||
!= header_fi->frame_or_sample_num + 1)) {
|
||||
FLACHeaderMarker *curr;
|
||||
int expected_frame_num, expected_sample_num;
|
||||
/* If there are frames in the middle we expect this deduction,
|
||||
as they are probably valid and this one follows it */
|
||||
|
||||
expected_frame_num = expected_sample_num = header_fi->frame_or_sample_num;
|
||||
curr = header;
|
||||
while (curr != child) {
|
||||
/* Ignore frames that failed all crc checks */
|
||||
for (i = 0; i < FLAC_MAX_SEQUENTIAL_HEADERS; i++) {
|
||||
if (curr->link_penalty[i] < FLAC_HEADER_CRC_FAIL_PENALTY) {
|
||||
expected_frame_num++;
|
||||
expected_sample_num += curr->fi.blocksize;
|
||||
break;
|
||||
}
|
||||
}
|
||||
curr = curr->next;
|
||||
}
|
||||
|
||||
if (expected_frame_num == child_fi->frame_or_sample_num ||
|
||||
expected_sample_num == child_fi->frame_or_sample_num)
|
||||
deduction_expected = deduction ? 0 : 1;
|
||||
|
||||
deduction += FLAC_HEADER_CHANGED_PENALTY;
|
||||
av_log(fpc->avctx, AV_LOG_WARNING + log_level_offset,
|
||||
"sample/frame number mismatch in adjacent frames\n");
|
||||
}
|
||||
|
||||
/* If we have suspicious headers, check the CRC between them */
|
||||
if (deduction && !deduction_expected) {
|
||||
FLACHeaderMarker *curr;
|
||||
int read_len;
|
||||
uint8_t *buf;
|
||||
uint32_t crc = 1;
|
||||
int inverted_test = 0;
|
||||
|
||||
/* Since CRC is expensive only do it if we haven't yet.
|
||||
This assumes a CRC penalty is greater than all other check penalties */
|
||||
curr = header->next;
|
||||
for (i = 0; i < FLAC_MAX_SEQUENTIAL_HEADERS && curr != child; i++)
|
||||
curr = curr->next;
|
||||
|
||||
if (header->link_penalty[i] < FLAC_HEADER_CRC_FAIL_PENALTY ||
|
||||
header->link_penalty[i] == FLAC_HEADER_NOT_PENALIZED_YET) {
|
||||
FLACHeaderMarker *start, *end;
|
||||
|
||||
/* Although overlapping chains are scored, the crc should never
|
||||
have to be computed twice for a single byte. */
|
||||
start = header;
|
||||
end = child;
|
||||
if (i > 0 &&
|
||||
header->link_penalty[i - 1] >= FLAC_HEADER_CRC_FAIL_PENALTY) {
|
||||
while (start->next != child)
|
||||
start = start->next;
|
||||
inverted_test = 1;
|
||||
} else if (i > 0 &&
|
||||
header->next->link_penalty[i-1] >=
|
||||
FLAC_HEADER_CRC_FAIL_PENALTY ) {
|
||||
end = header->next;
|
||||
inverted_test = 1;
|
||||
}
|
||||
|
||||
read_len = end->offset - start->offset;
|
||||
buf = flac_fifo_read(fpc, start->offset, &read_len);
|
||||
crc = av_crc(av_crc_get_table(AV_CRC_16_ANSI), 0, buf, read_len);
|
||||
read_len = (end->offset - start->offset) - read_len;
|
||||
|
||||
if (read_len) {
|
||||
buf = flac_fifo_read(fpc, end->offset - read_len, &read_len);
|
||||
crc = av_crc(av_crc_get_table(AV_CRC_16_ANSI), crc, buf, read_len);
|
||||
}
|
||||
}
|
||||
|
||||
if (!crc ^ !inverted_test) {
|
||||
deduction += FLAC_HEADER_CRC_FAIL_PENALTY;
|
||||
av_log(fpc->avctx, AV_LOG_WARNING + log_level_offset,
|
||||
"crc check failed from offset %i (frame %"PRId64") to %i (frame %"PRId64")\n",
|
||||
header->offset, header_fi->frame_or_sample_num,
|
||||
child->offset, child_fi->frame_or_sample_num);
|
||||
}
|
||||
}
|
||||
return deduction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Score a header.
|
||||
*
|
||||
* Give FLAC_HEADER_BASE_SCORE points to a frame for existing.
|
||||
* If it has children, (subsequent frames of which the preceding CRC footer
|
||||
* validates against this one,) then take the maximum score of the children,
|
||||
* with a penalty of FLAC_HEADER_CHANGED_PENALTY applied for each change to
|
||||
* bps, sample rate, channels, but not decorrelation mode, or blocksize,
|
||||
* because it can change often.
|
||||
**/
|
||||
static int score_header(FLACParseContext *fpc, FLACHeaderMarker *header)
|
||||
{
|
||||
FLACHeaderMarker *child;
|
||||
int dist = 0;
|
||||
int child_score;
|
||||
int base_score = FLAC_HEADER_BASE_SCORE;
|
||||
if (header->max_score != FLAC_HEADER_NOT_SCORED_YET)
|
||||
return header->max_score;
|
||||
|
||||
/* Modify the base score with changes from the last output header */
|
||||
if (fpc->last_fi_valid) {
|
||||
/* Silence the log since this will be repeated if selected */
|
||||
base_score -= check_header_fi_mismatch(fpc, &fpc->last_fi, &header->fi,
|
||||
AV_LOG_DEBUG);
|
||||
}
|
||||
|
||||
header->max_score = base_score;
|
||||
|
||||
/* Check and compute the children's scores. */
|
||||
child = header->next;
|
||||
for (dist = 0; dist < FLAC_MAX_SEQUENTIAL_HEADERS && child; dist++) {
|
||||
/* Look at the child's frame header info and penalize suspicious
|
||||
changes between the headers. */
|
||||
if (header->link_penalty[dist] == FLAC_HEADER_NOT_PENALIZED_YET) {
|
||||
header->link_penalty[dist] = check_header_mismatch(fpc, header,
|
||||
child, AV_LOG_DEBUG);
|
||||
}
|
||||
child_score = score_header(fpc, child) - header->link_penalty[dist];
|
||||
|
||||
if (FLAC_HEADER_BASE_SCORE + child_score > header->max_score) {
|
||||
/* Keep the child because the frame scoring is dynamic. */
|
||||
header->best_child = child;
|
||||
header->max_score = base_score + child_score;
|
||||
}
|
||||
child = child->next;
|
||||
}
|
||||
|
||||
return header->max_score;
|
||||
}
|
||||
|
||||
static void score_sequences(FLACParseContext *fpc)
|
||||
{
|
||||
FLACHeaderMarker *curr;
|
||||
int best_score = 0;//FLAC_HEADER_NOT_SCORED_YET;
|
||||
/* First pass to clear all old scores. */
|
||||
for (curr = fpc->headers; curr; curr = curr->next)
|
||||
curr->max_score = FLAC_HEADER_NOT_SCORED_YET;
|
||||
|
||||
/* Do a second pass to score them all. */
|
||||
for (curr = fpc->headers; curr; curr = curr->next) {
|
||||
if (score_header(fpc, curr) > best_score) {
|
||||
fpc->best_header = curr;
|
||||
best_score = curr->max_score;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int get_best_header(FLACParseContext* fpc, const uint8_t **poutbuf,
|
||||
int *poutbuf_size)
|
||||
{
|
||||
FLACHeaderMarker *header = fpc->best_header;
|
||||
FLACHeaderMarker *child = header->best_child;
|
||||
if (!child) {
|
||||
*poutbuf_size = av_fifo_size(fpc->fifo_buf) - header->offset;
|
||||
} else {
|
||||
*poutbuf_size = child->offset - header->offset;
|
||||
|
||||
/* If the child has suspicious changes, log them */
|
||||
check_header_mismatch(fpc, header, child, 0);
|
||||
}
|
||||
|
||||
if (header->fi.channels != fpc->avctx->channels ||
|
||||
!fpc->avctx->channel_layout) {
|
||||
fpc->avctx->channels = header->fi.channels;
|
||||
ff_flac_set_channel_layout(fpc->avctx);
|
||||
}
|
||||
fpc->avctx->sample_rate = header->fi.samplerate;
|
||||
fpc->pc->duration = header->fi.blocksize;
|
||||
*poutbuf = flac_fifo_read_wrap(fpc, header->offset, *poutbuf_size,
|
||||
&fpc->wrap_buf,
|
||||
&fpc->wrap_buf_allocated_size);
|
||||
|
||||
|
||||
if (fpc->pc->flags & PARSER_FLAG_USE_CODEC_TS){
|
||||
if (header->fi.is_var_size)
|
||||
fpc->pc->pts = header->fi.frame_or_sample_num;
|
||||
else if (header->best_child)
|
||||
fpc->pc->pts = header->fi.frame_or_sample_num * header->fi.blocksize;
|
||||
}
|
||||
|
||||
fpc->best_header_valid = 0;
|
||||
fpc->last_fi_valid = 1;
|
||||
fpc->last_fi = header->fi;
|
||||
|
||||
/* Return the negative overread index so the client can compute pos.
|
||||
This should be the amount overread to the beginning of the child */
|
||||
if (child)
|
||||
return child->offset - av_fifo_size(fpc->fifo_buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flac_parse(AVCodecParserContext *s, AVCodecContext *avctx,
|
||||
const uint8_t **poutbuf, int *poutbuf_size,
|
||||
const uint8_t *buf, int buf_size)
|
||||
{
|
||||
FLACParseContext *fpc = s->priv_data;
|
||||
FLACHeaderMarker *curr;
|
||||
int nb_headers;
|
||||
const uint8_t *read_end = buf;
|
||||
const uint8_t *read_start = buf;
|
||||
|
||||
if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) {
|
||||
FLACFrameInfo fi;
|
||||
if (frame_header_is_valid(avctx, buf, &fi)) {
|
||||
s->duration = fi.blocksize;
|
||||
if (!avctx->sample_rate)
|
||||
avctx->sample_rate = fi.samplerate;
|
||||
if (fpc->pc->flags & PARSER_FLAG_USE_CODEC_TS){
|
||||
fpc->pc->pts = fi.frame_or_sample_num;
|
||||
if (!fi.is_var_size)
|
||||
fpc->pc->pts *= fi.blocksize;
|
||||
}
|
||||
}
|
||||
*poutbuf = buf;
|
||||
*poutbuf_size = buf_size;
|
||||
return buf_size;
|
||||
}
|
||||
|
||||
fpc->avctx = avctx;
|
||||
if (fpc->best_header_valid)
|
||||
return get_best_header(fpc, poutbuf, poutbuf_size);
|
||||
|
||||
/* If a best_header was found last call remove it with the buffer data. */
|
||||
if (fpc->best_header && fpc->best_header->best_child) {
|
||||
FLACHeaderMarker *temp;
|
||||
FLACHeaderMarker *best_child = fpc->best_header->best_child;
|
||||
|
||||
/* Remove headers in list until the end of the best_header. */
|
||||
for (curr = fpc->headers; curr != best_child; curr = temp) {
|
||||
if (curr != fpc->best_header) {
|
||||
av_log(avctx, AV_LOG_DEBUG,
|
||||
"dropping low score %i frame header from offset %i to %i\n",
|
||||
curr->max_score, curr->offset, curr->next->offset);
|
||||
}
|
||||
temp = curr->next;
|
||||
av_freep(&curr->link_penalty);
|
||||
av_free(curr);
|
||||
fpc->nb_headers_buffered--;
|
||||
}
|
||||
/* Release returned data from ring buffer. */
|
||||
av_fifo_drain(fpc->fifo_buf, best_child->offset);
|
||||
|
||||
/* Fix the offset for the headers remaining to match the new buffer. */
|
||||
for (curr = best_child->next; curr; curr = curr->next)
|
||||
curr->offset -= best_child->offset;
|
||||
|
||||
fpc->nb_headers_buffered--;
|
||||
best_child->offset = 0;
|
||||
fpc->headers = best_child;
|
||||
if (fpc->nb_headers_buffered >= FLAC_MIN_HEADERS) {
|
||||
fpc->best_header = best_child;
|
||||
return get_best_header(fpc, poutbuf, poutbuf_size);
|
||||
}
|
||||
fpc->best_header = NULL;
|
||||
} else if (fpc->best_header) {
|
||||
/* No end frame no need to delete the buffer; probably eof */
|
||||
FLACHeaderMarker *temp;
|
||||
|
||||
for (curr = fpc->headers; curr != fpc->best_header; curr = temp) {
|
||||
temp = curr->next;
|
||||
av_freep(&curr->link_penalty);
|
||||
av_free(curr);
|
||||
}
|
||||
fpc->headers = fpc->best_header->next;
|
||||
av_freep(&fpc->best_header->link_penalty);
|
||||
av_freep(&fpc->best_header);
|
||||
}
|
||||
|
||||
/* Find and score new headers. */
|
||||
/* buf_size is to zero when padding, so check for this since we do */
|
||||
/* not want to try to read more input once we have found the end. */
|
||||
/* Note that as (non-modified) parameters, buf can be non-NULL, */
|
||||
/* while buf_size is 0. */
|
||||
while ((buf && buf_size && read_end < buf + buf_size &&
|
||||
fpc->nb_headers_buffered < FLAC_MIN_HEADERS)
|
||||
|| ((!buf || !buf_size) && !fpc->end_padded)) {
|
||||
int start_offset;
|
||||
|
||||
/* Pad the end once if EOF, to check the final region for headers. */
|
||||
if (!buf || !buf_size) {
|
||||
fpc->end_padded = 1;
|
||||
buf_size = MAX_FRAME_HEADER_SIZE;
|
||||
read_end = read_start + MAX_FRAME_HEADER_SIZE;
|
||||
} else {
|
||||
/* The maximum read size is the upper-bound of what the parser
|
||||
needs to have the required number of frames buffered */
|
||||
int nb_desired = FLAC_MIN_HEADERS - fpc->nb_headers_buffered + 1;
|
||||
read_end = read_end + FFMIN(buf + buf_size - read_end,
|
||||
nb_desired * FLAC_AVG_FRAME_SIZE);
|
||||
}
|
||||
|
||||
if (!av_fifo_space(fpc->fifo_buf) &&
|
||||
av_fifo_size(fpc->fifo_buf) / FLAC_AVG_FRAME_SIZE >
|
||||
fpc->nb_headers_buffered * 20) {
|
||||
/* There is less than one valid flac header buffered for 20 headers
|
||||
* buffered. Therefore the fifo is most likely filled with invalid
|
||||
* data and the input is not a flac file. */
|
||||
goto handle_error;
|
||||
}
|
||||
|
||||
/* Fill the buffer. */
|
||||
if ( av_fifo_space(fpc->fifo_buf) < read_end - read_start
|
||||
&& av_fifo_realloc2(fpc->fifo_buf, (read_end - read_start) + 2*av_fifo_size(fpc->fifo_buf)) < 0) {
|
||||
av_log(avctx, AV_LOG_ERROR,
|
||||
"couldn't reallocate buffer of size %"PTRDIFF_SPECIFIER"\n",
|
||||
(read_end - read_start) + av_fifo_size(fpc->fifo_buf));
|
||||
goto handle_error;
|
||||
}
|
||||
|
||||
if (buf && buf_size) {
|
||||
av_fifo_generic_write(fpc->fifo_buf, (void*) read_start,
|
||||
read_end - read_start, NULL);
|
||||
} else {
|
||||
int8_t pad[MAX_FRAME_HEADER_SIZE] = { 0 };
|
||||
av_fifo_generic_write(fpc->fifo_buf, (void*) pad, sizeof(pad), NULL);
|
||||
}
|
||||
|
||||
/* Tag headers and update sequences. */
|
||||
start_offset = av_fifo_size(fpc->fifo_buf) -
|
||||
((read_end - read_start) + (MAX_FRAME_HEADER_SIZE - 1));
|
||||
start_offset = FFMAX(0, start_offset);
|
||||
nb_headers = find_new_headers(fpc, start_offset);
|
||||
|
||||
if (nb_headers < 0) {
|
||||
av_log(avctx, AV_LOG_ERROR,
|
||||
"find_new_headers couldn't allocate FLAC header\n");
|
||||
goto handle_error;
|
||||
}
|
||||
|
||||
fpc->nb_headers_buffered = nb_headers;
|
||||
/* Wait till FLAC_MIN_HEADERS to output a valid frame. */
|
||||
if (!fpc->end_padded && fpc->nb_headers_buffered < FLAC_MIN_HEADERS) {
|
||||
if (buf && read_end < buf + buf_size) {
|
||||
read_start = read_end;
|
||||
continue;
|
||||
} else {
|
||||
goto handle_error;
|
||||
}
|
||||
}
|
||||
|
||||
/* If headers found, update the scores since we have longer chains. */
|
||||
if (fpc->end_padded || fpc->nb_headers_found)
|
||||
score_sequences(fpc);
|
||||
|
||||
/* restore the state pre-padding */
|
||||
if (fpc->end_padded) {
|
||||
int warp = fpc->fifo_buf->wptr - fpc->fifo_buf->buffer < MAX_FRAME_HEADER_SIZE;
|
||||
/* HACK: drain the tail of the fifo */
|
||||
fpc->fifo_buf->wptr -= MAX_FRAME_HEADER_SIZE;
|
||||
fpc->fifo_buf->wndx -= MAX_FRAME_HEADER_SIZE;
|
||||
if (warp) {
|
||||
fpc->fifo_buf->wptr += fpc->fifo_buf->end -
|
||||
fpc->fifo_buf->buffer;
|
||||
}
|
||||
buf_size = 0;
|
||||
read_start = read_end = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for (curr = fpc->headers; curr; curr = curr->next) {
|
||||
if (curr->max_score > 0 &&
|
||||
(!fpc->best_header || curr->max_score > fpc->best_header->max_score)) {
|
||||
fpc->best_header = curr;
|
||||
}
|
||||
}
|
||||
|
||||
if (fpc->best_header) {
|
||||
fpc->best_header_valid = 1;
|
||||
if (fpc->best_header->offset > 0) {
|
||||
/* Output a junk frame. */
|
||||
av_log(avctx, AV_LOG_DEBUG, "Junk frame till offset %i\n",
|
||||
fpc->best_header->offset);
|
||||
|
||||
/* Set duration to 0. It is unknown or invalid in a junk frame. */
|
||||
s->duration = 0;
|
||||
*poutbuf_size = fpc->best_header->offset;
|
||||
*poutbuf = flac_fifo_read_wrap(fpc, 0, *poutbuf_size,
|
||||
&fpc->wrap_buf,
|
||||
&fpc->wrap_buf_allocated_size);
|
||||
return buf_size ? (read_end - buf) : (fpc->best_header->offset -
|
||||
av_fifo_size(fpc->fifo_buf));
|
||||
}
|
||||
if (!buf_size)
|
||||
return get_best_header(fpc, poutbuf, poutbuf_size);
|
||||
}
|
||||
|
||||
handle_error:
|
||||
*poutbuf = NULL;
|
||||
*poutbuf_size = 0;
|
||||
return buf_size ? read_end - buf : 0;
|
||||
}
|
||||
|
||||
static av_cold int flac_parse_init(AVCodecParserContext *c)
|
||||
{
|
||||
FLACParseContext *fpc = c->priv_data;
|
||||
fpc->pc = c;
|
||||
/* There will generally be FLAC_MIN_HEADERS buffered in the fifo before
|
||||
it drains. This is allocated early to avoid slow reallocation. */
|
||||
fpc->fifo_buf = av_fifo_alloc_array(FLAC_MIN_HEADERS + 3, FLAC_AVG_FRAME_SIZE);
|
||||
if (!fpc->fifo_buf) {
|
||||
av_log(fpc->avctx, AV_LOG_ERROR,
|
||||
"couldn't allocate fifo_buf\n");
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void flac_parse_close(AVCodecParserContext *c)
|
||||
{
|
||||
FLACParseContext *fpc = c->priv_data;
|
||||
FLACHeaderMarker *curr = fpc->headers, *temp;
|
||||
|
||||
while (curr) {
|
||||
temp = curr->next;
|
||||
av_freep(&curr->link_penalty);
|
||||
av_free(curr);
|
||||
curr = temp;
|
||||
}
|
||||
av_fifo_freep(&fpc->fifo_buf);
|
||||
av_freep(&fpc->wrap_buf);
|
||||
}
|
||||
|
||||
AVCodecParser ff_flac_parser = {
|
||||
.codec_ids = { AV_CODEC_ID_FLAC },
|
||||
.priv_data_size = sizeof(FLACParseContext),
|
||||
.parser_init = flac_parse_init,
|
||||
.parser_parse = flac_parse,
|
||||
.parser_close = flac_parse_close,
|
||||
};
|
33
media/ffvpx/libavcodec/flacdata.c
Normal file
33
media/ffvpx/libavcodec/flacdata.c
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* FLAC data
|
||||
* Copyright (c) 2003 Alex Beregszaszi
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
const int ff_flac_sample_rate_table[16] =
|
||||
{ 0,
|
||||
88200, 176400, 192000,
|
||||
8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000,
|
||||
0, 0, 0, 0 };
|
||||
|
||||
const int32_t ff_flac_blocksize_table[16] = {
|
||||
0, 192, 576<<0, 576<<1, 576<<2, 576<<3, 0, 0,
|
||||
256<<0, 256<<1, 256<<2, 256<<3, 256<<4, 256<<5, 256<<6, 256<<7
|
||||
};
|
31
media/ffvpx/libavcodec/flacdata.h
Normal file
31
media/ffvpx/libavcodec/flacdata.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* FLAC data header
|
||||
* Copyright (c) 2003 Alex Beregszaszi
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_FLACDATA_H
|
||||
#define AVCODEC_FLACDATA_H
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
extern const int ff_flac_sample_rate_table[16];
|
||||
|
||||
extern const int32_t ff_flac_blocksize_table[16];
|
||||
|
||||
#endif /* AVCODEC_FLACDATA_H */
|
677
media/ffvpx/libavcodec/flacdec.c
Normal file
677
media/ffvpx/libavcodec/flacdec.c
Normal file
@ -0,0 +1,677 @@
|
||||
/*
|
||||
* FLAC (Free Lossless Audio Codec) decoder
|
||||
* Copyright (c) 2003 Alex Beregszaszi
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* FLAC (Free Lossless Audio Codec) decoder
|
||||
* @author Alex Beregszaszi
|
||||
* @see http://flac.sourceforge.net/
|
||||
*
|
||||
* This decoder can be used in 1 of 2 ways: Either raw FLAC data can be fed
|
||||
* through, starting from the initial 'fLaC' signature; or by passing the
|
||||
* 34-byte streaminfo structure through avctx->extradata[_size] followed
|
||||
* by data starting with the 0xFFF8 marker.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "libavutil/avassert.h"
|
||||
#include "libavutil/crc.h"
|
||||
#include "libavutil/opt.h"
|
||||
#include "avcodec.h"
|
||||
#include "internal.h"
|
||||
#include "get_bits.h"
|
||||
#include "bytestream.h"
|
||||
#include "golomb.h"
|
||||
#include "flac.h"
|
||||
#include "flacdata.h"
|
||||
#include "flacdsp.h"
|
||||
#include "thread.h"
|
||||
#include "unary.h"
|
||||
|
||||
|
||||
typedef struct FLACContext {
|
||||
AVClass *class;
|
||||
struct FLACStreaminfo flac_stream_info;
|
||||
|
||||
AVCodecContext *avctx; ///< parent AVCodecContext
|
||||
GetBitContext gb; ///< GetBitContext initialized to start at the current frame
|
||||
|
||||
int blocksize; ///< number of samples in the current frame
|
||||
int sample_shift; ///< shift required to make output samples 16-bit or 32-bit
|
||||
int ch_mode; ///< channel decorrelation type in the current frame
|
||||
int got_streaminfo; ///< indicates if the STREAMINFO has been read
|
||||
|
||||
int32_t *decoded[FLAC_MAX_CHANNELS]; ///< decoded samples
|
||||
uint8_t *decoded_buffer;
|
||||
unsigned int decoded_buffer_size;
|
||||
int buggy_lpc; ///< use workaround for old lavc encoded files
|
||||
|
||||
FLACDSPContext dsp;
|
||||
} FLACContext;
|
||||
|
||||
static int allocate_buffers(FLACContext *s);
|
||||
|
||||
static void flac_set_bps(FLACContext *s)
|
||||
{
|
||||
enum AVSampleFormat req = s->avctx->request_sample_fmt;
|
||||
int need32 = s->flac_stream_info.bps > 16;
|
||||
int want32 = av_get_bytes_per_sample(req) > 2;
|
||||
int planar = av_sample_fmt_is_planar(req);
|
||||
|
||||
if (need32 || want32) {
|
||||
if (planar)
|
||||
s->avctx->sample_fmt = AV_SAMPLE_FMT_S32P;
|
||||
else
|
||||
s->avctx->sample_fmt = AV_SAMPLE_FMT_S32;
|
||||
s->sample_shift = 32 - s->flac_stream_info.bps;
|
||||
} else {
|
||||
if (planar)
|
||||
s->avctx->sample_fmt = AV_SAMPLE_FMT_S16P;
|
||||
else
|
||||
s->avctx->sample_fmt = AV_SAMPLE_FMT_S16;
|
||||
s->sample_shift = 16 - s->flac_stream_info.bps;
|
||||
}
|
||||
}
|
||||
|
||||
static av_cold int flac_decode_init(AVCodecContext *avctx)
|
||||
{
|
||||
enum FLACExtradataFormat format;
|
||||
uint8_t *streaminfo;
|
||||
int ret;
|
||||
FLACContext *s = avctx->priv_data;
|
||||
s->avctx = avctx;
|
||||
|
||||
/* for now, the raw FLAC header is allowed to be passed to the decoder as
|
||||
frame data instead of extradata. */
|
||||
if (!avctx->extradata)
|
||||
return 0;
|
||||
|
||||
if (!ff_flac_is_extradata_valid(avctx, &format, &streaminfo))
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
/* initialize based on the demuxer-supplied streamdata header */
|
||||
ff_flac_parse_streaminfo(avctx, &s->flac_stream_info, streaminfo);
|
||||
ret = allocate_buffers(s);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
flac_set_bps(s);
|
||||
ff_flacdsp_init(&s->dsp, avctx->sample_fmt,
|
||||
s->flac_stream_info.channels, s->flac_stream_info.bps);
|
||||
s->got_streaminfo = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dump_headers(AVCodecContext *avctx, FLACStreaminfo *s)
|
||||
{
|
||||
av_log(avctx, AV_LOG_DEBUG, " Max Blocksize: %d\n", s->max_blocksize);
|
||||
av_log(avctx, AV_LOG_DEBUG, " Max Framesize: %d\n", s->max_framesize);
|
||||
av_log(avctx, AV_LOG_DEBUG, " Samplerate: %d\n", s->samplerate);
|
||||
av_log(avctx, AV_LOG_DEBUG, " Channels: %d\n", s->channels);
|
||||
av_log(avctx, AV_LOG_DEBUG, " Bits: %d\n", s->bps);
|
||||
}
|
||||
|
||||
static int allocate_buffers(FLACContext *s)
|
||||
{
|
||||
int buf_size;
|
||||
int ret;
|
||||
|
||||
av_assert0(s->flac_stream_info.max_blocksize);
|
||||
|
||||
buf_size = av_samples_get_buffer_size(NULL, s->flac_stream_info.channels,
|
||||
s->flac_stream_info.max_blocksize,
|
||||
AV_SAMPLE_FMT_S32P, 0);
|
||||
if (buf_size < 0)
|
||||
return buf_size;
|
||||
|
||||
av_fast_malloc(&s->decoded_buffer, &s->decoded_buffer_size, buf_size);
|
||||
if (!s->decoded_buffer)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
ret = av_samples_fill_arrays((uint8_t **)s->decoded, NULL,
|
||||
s->decoded_buffer,
|
||||
s->flac_stream_info.channels,
|
||||
s->flac_stream_info.max_blocksize,
|
||||
AV_SAMPLE_FMT_S32P, 0);
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the STREAMINFO from an inline header.
|
||||
* @param s the flac decoding context
|
||||
* @param buf input buffer, starting with the "fLaC" marker
|
||||
* @param buf_size buffer size
|
||||
* @return non-zero if metadata is invalid
|
||||
*/
|
||||
static int parse_streaminfo(FLACContext *s, const uint8_t *buf, int buf_size)
|
||||
{
|
||||
int metadata_type, metadata_size, ret;
|
||||
|
||||
if (buf_size < FLAC_STREAMINFO_SIZE+8) {
|
||||
/* need more data */
|
||||
return 0;
|
||||
}
|
||||
flac_parse_block_header(&buf[4], NULL, &metadata_type, &metadata_size);
|
||||
if (metadata_type != FLAC_METADATA_TYPE_STREAMINFO ||
|
||||
metadata_size != FLAC_STREAMINFO_SIZE) {
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
ff_flac_parse_streaminfo(s->avctx, &s->flac_stream_info, &buf[8]);
|
||||
ret = allocate_buffers(s);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
flac_set_bps(s);
|
||||
ff_flacdsp_init(&s->dsp, s->avctx->sample_fmt,
|
||||
s->flac_stream_info.channels, s->flac_stream_info.bps);
|
||||
s->got_streaminfo = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the size of an inline header.
|
||||
* @param buf input buffer, starting with the "fLaC" marker
|
||||
* @param buf_size buffer size
|
||||
* @return number of bytes in the header, or 0 if more data is needed
|
||||
*/
|
||||
static int get_metadata_size(const uint8_t *buf, int buf_size)
|
||||
{
|
||||
int metadata_last, metadata_size;
|
||||
const uint8_t *buf_end = buf + buf_size;
|
||||
|
||||
buf += 4;
|
||||
do {
|
||||
if (buf_end - buf < 4)
|
||||
return 0;
|
||||
flac_parse_block_header(buf, &metadata_last, NULL, &metadata_size);
|
||||
buf += 4;
|
||||
if (buf_end - buf < metadata_size) {
|
||||
/* need more data in order to read the complete header */
|
||||
return 0;
|
||||
}
|
||||
buf += metadata_size;
|
||||
} while (!metadata_last);
|
||||
|
||||
return buf_size - (buf_end - buf);
|
||||
}
|
||||
|
||||
static int decode_residuals(FLACContext *s, int32_t *decoded, int pred_order)
|
||||
{
|
||||
int i, tmp, partition, method_type, rice_order;
|
||||
int rice_bits, rice_esc;
|
||||
int samples;
|
||||
|
||||
method_type = get_bits(&s->gb, 2);
|
||||
if (method_type > 1) {
|
||||
av_log(s->avctx, AV_LOG_ERROR, "illegal residual coding method %d\n",
|
||||
method_type);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
rice_order = get_bits(&s->gb, 4);
|
||||
|
||||
samples= s->blocksize >> rice_order;
|
||||
if (samples << rice_order != s->blocksize) {
|
||||
av_log(s->avctx, AV_LOG_ERROR, "invalid rice order: %i blocksize %i\n",
|
||||
rice_order, s->blocksize);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
if (pred_order > samples) {
|
||||
av_log(s->avctx, AV_LOG_ERROR, "invalid predictor order: %i > %i\n",
|
||||
pred_order, samples);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
rice_bits = 4 + method_type;
|
||||
rice_esc = (1 << rice_bits) - 1;
|
||||
|
||||
decoded += pred_order;
|
||||
i= pred_order;
|
||||
for (partition = 0; partition < (1 << rice_order); partition++) {
|
||||
tmp = get_bits(&s->gb, rice_bits);
|
||||
if (tmp == rice_esc) {
|
||||
tmp = get_bits(&s->gb, 5);
|
||||
for (; i < samples; i++)
|
||||
*decoded++ = get_sbits_long(&s->gb, tmp);
|
||||
} else {
|
||||
for (; i < samples; i++) {
|
||||
*decoded++ = get_sr_golomb_flac(&s->gb, tmp, INT_MAX, 0);
|
||||
}
|
||||
}
|
||||
i= 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int decode_subframe_fixed(FLACContext *s, int32_t *decoded,
|
||||
int pred_order, int bps)
|
||||
{
|
||||
const int blocksize = s->blocksize;
|
||||
int av_uninit(a), av_uninit(b), av_uninit(c), av_uninit(d), i;
|
||||
int ret;
|
||||
|
||||
/* warm up samples */
|
||||
for (i = 0; i < pred_order; i++) {
|
||||
decoded[i] = get_sbits_long(&s->gb, bps);
|
||||
}
|
||||
|
||||
if ((ret = decode_residuals(s, decoded, pred_order)) < 0)
|
||||
return ret;
|
||||
|
||||
if (pred_order > 0)
|
||||
a = decoded[pred_order-1];
|
||||
if (pred_order > 1)
|
||||
b = a - decoded[pred_order-2];
|
||||
if (pred_order > 2)
|
||||
c = b - decoded[pred_order-2] + decoded[pred_order-3];
|
||||
if (pred_order > 3)
|
||||
d = c - decoded[pred_order-2] + 2*decoded[pred_order-3] - decoded[pred_order-4];
|
||||
|
||||
switch (pred_order) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
for (i = pred_order; i < blocksize; i++)
|
||||
decoded[i] = a += decoded[i];
|
||||
break;
|
||||
case 2:
|
||||
for (i = pred_order; i < blocksize; i++)
|
||||
decoded[i] = a += b += decoded[i];
|
||||
break;
|
||||
case 3:
|
||||
for (i = pred_order; i < blocksize; i++)
|
||||
decoded[i] = a += b += c += decoded[i];
|
||||
break;
|
||||
case 4:
|
||||
for (i = pred_order; i < blocksize; i++)
|
||||
decoded[i] = a += b += c += d += decoded[i];
|
||||
break;
|
||||
default:
|
||||
av_log(s->avctx, AV_LOG_ERROR, "illegal pred order %d\n", pred_order);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lpc_analyze_remodulate(int32_t *decoded, const int coeffs[32],
|
||||
int order, int qlevel, int len, int bps)
|
||||
{
|
||||
int i, j;
|
||||
int ebps = 1 << (bps-1);
|
||||
unsigned sigma = 0;
|
||||
|
||||
for (i = order; i < len; i++)
|
||||
sigma |= decoded[i] + ebps;
|
||||
|
||||
if (sigma < 2*ebps)
|
||||
return;
|
||||
|
||||
for (i = len - 1; i >= order; i--) {
|
||||
int64_t p = 0;
|
||||
for (j = 0; j < order; j++)
|
||||
p += coeffs[j] * (int64_t)decoded[i-order+j];
|
||||
decoded[i] -= p >> qlevel;
|
||||
}
|
||||
for (i = order; i < len; i++, decoded++) {
|
||||
int32_t p = 0;
|
||||
for (j = 0; j < order; j++)
|
||||
p += coeffs[j] * (uint32_t)decoded[j];
|
||||
decoded[j] += p >> qlevel;
|
||||
}
|
||||
}
|
||||
|
||||
static int decode_subframe_lpc(FLACContext *s, int32_t *decoded, int pred_order,
|
||||
int bps)
|
||||
{
|
||||
int i, ret;
|
||||
int coeff_prec, qlevel;
|
||||
int coeffs[32];
|
||||
|
||||
/* warm up samples */
|
||||
for (i = 0; i < pred_order; i++) {
|
||||
decoded[i] = get_sbits_long(&s->gb, bps);
|
||||
}
|
||||
|
||||
coeff_prec = get_bits(&s->gb, 4) + 1;
|
||||
if (coeff_prec == 16) {
|
||||
av_log(s->avctx, AV_LOG_ERROR, "invalid coeff precision\n");
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
qlevel = get_sbits(&s->gb, 5);
|
||||
if (qlevel < 0) {
|
||||
av_log(s->avctx, AV_LOG_ERROR, "qlevel %d not supported, maybe buggy stream\n",
|
||||
qlevel);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
for (i = 0; i < pred_order; i++) {
|
||||
coeffs[pred_order - i - 1] = get_sbits(&s->gb, coeff_prec);
|
||||
}
|
||||
|
||||
if ((ret = decode_residuals(s, decoded, pred_order)) < 0)
|
||||
return ret;
|
||||
|
||||
if ( ( s->buggy_lpc && s->flac_stream_info.bps <= 16)
|
||||
|| ( !s->buggy_lpc && bps <= 16
|
||||
&& bps + coeff_prec + av_log2(pred_order) <= 32)) {
|
||||
s->dsp.lpc16(decoded, coeffs, pred_order, qlevel, s->blocksize);
|
||||
} else {
|
||||
s->dsp.lpc32(decoded, coeffs, pred_order, qlevel, s->blocksize);
|
||||
if (s->flac_stream_info.bps <= 16)
|
||||
lpc_analyze_remodulate(decoded, coeffs, pred_order, qlevel, s->blocksize, bps);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int decode_subframe(FLACContext *s, int channel)
|
||||
{
|
||||
int32_t *decoded = s->decoded[channel];
|
||||
int type, wasted = 0;
|
||||
int bps = s->flac_stream_info.bps;
|
||||
int i, tmp, ret;
|
||||
|
||||
if (channel == 0) {
|
||||
if (s->ch_mode == FLAC_CHMODE_RIGHT_SIDE)
|
||||
bps++;
|
||||
} else {
|
||||
if (s->ch_mode == FLAC_CHMODE_LEFT_SIDE || s->ch_mode == FLAC_CHMODE_MID_SIDE)
|
||||
bps++;
|
||||
}
|
||||
|
||||
if (get_bits1(&s->gb)) {
|
||||
av_log(s->avctx, AV_LOG_ERROR, "invalid subframe padding\n");
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
type = get_bits(&s->gb, 6);
|
||||
|
||||
if (get_bits1(&s->gb)) {
|
||||
int left = get_bits_left(&s->gb);
|
||||
if ( left <= 0 ||
|
||||
(left < bps && !show_bits_long(&s->gb, left)) ||
|
||||
!show_bits_long(&s->gb, bps)) {
|
||||
av_log(s->avctx, AV_LOG_ERROR,
|
||||
"Invalid number of wasted bits > available bits (%d) - left=%d\n",
|
||||
bps, left);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
wasted = 1 + get_unary(&s->gb, 1, get_bits_left(&s->gb));
|
||||
bps -= wasted;
|
||||
}
|
||||
if (bps > 32) {
|
||||
avpriv_report_missing_feature(s->avctx, "Decorrelated bit depth > 32");
|
||||
return AVERROR_PATCHWELCOME;
|
||||
}
|
||||
|
||||
//FIXME use av_log2 for types
|
||||
if (type == 0) {
|
||||
tmp = get_sbits_long(&s->gb, bps);
|
||||
for (i = 0; i < s->blocksize; i++)
|
||||
decoded[i] = tmp;
|
||||
} else if (type == 1) {
|
||||
for (i = 0; i < s->blocksize; i++)
|
||||
decoded[i] = get_sbits_long(&s->gb, bps);
|
||||
} else if ((type >= 8) && (type <= 12)) {
|
||||
if ((ret = decode_subframe_fixed(s, decoded, type & ~0x8, bps)) < 0)
|
||||
return ret;
|
||||
} else if (type >= 32) {
|
||||
if ((ret = decode_subframe_lpc(s, decoded, (type & ~0x20)+1, bps)) < 0)
|
||||
return ret;
|
||||
} else {
|
||||
av_log(s->avctx, AV_LOG_ERROR, "invalid coding type\n");
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
if (wasted) {
|
||||
int i;
|
||||
for (i = 0; i < s->blocksize; i++)
|
||||
decoded[i] <<= wasted;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int decode_frame(FLACContext *s)
|
||||
{
|
||||
int i, ret;
|
||||
GetBitContext *gb = &s->gb;
|
||||
FLACFrameInfo fi;
|
||||
|
||||
if ((ret = ff_flac_decode_frame_header(s->avctx, gb, &fi, 0)) < 0) {
|
||||
av_log(s->avctx, AV_LOG_ERROR, "invalid frame header\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ( s->flac_stream_info.channels
|
||||
&& fi.channels != s->flac_stream_info.channels
|
||||
&& s->got_streaminfo) {
|
||||
s->flac_stream_info.channels = s->avctx->channels = fi.channels;
|
||||
ff_flac_set_channel_layout(s->avctx);
|
||||
ret = allocate_buffers(s);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
s->flac_stream_info.channels = s->avctx->channels = fi.channels;
|
||||
if (!s->avctx->channel_layout)
|
||||
ff_flac_set_channel_layout(s->avctx);
|
||||
s->ch_mode = fi.ch_mode;
|
||||
|
||||
if (!s->flac_stream_info.bps && !fi.bps) {
|
||||
av_log(s->avctx, AV_LOG_ERROR, "bps not found in STREAMINFO or frame header\n");
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
if (!fi.bps) {
|
||||
fi.bps = s->flac_stream_info.bps;
|
||||
} else if (s->flac_stream_info.bps && fi.bps != s->flac_stream_info.bps) {
|
||||
av_log(s->avctx, AV_LOG_ERROR, "switching bps mid-stream is not "
|
||||
"supported\n");
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
if (!s->flac_stream_info.bps) {
|
||||
s->flac_stream_info.bps = s->avctx->bits_per_raw_sample = fi.bps;
|
||||
flac_set_bps(s);
|
||||
}
|
||||
|
||||
if (!s->flac_stream_info.max_blocksize)
|
||||
s->flac_stream_info.max_blocksize = FLAC_MAX_BLOCKSIZE;
|
||||
if (fi.blocksize > s->flac_stream_info.max_blocksize) {
|
||||
av_log(s->avctx, AV_LOG_ERROR, "blocksize %d > %d\n", fi.blocksize,
|
||||
s->flac_stream_info.max_blocksize);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
s->blocksize = fi.blocksize;
|
||||
|
||||
if (!s->flac_stream_info.samplerate && !fi.samplerate) {
|
||||
av_log(s->avctx, AV_LOG_ERROR, "sample rate not found in STREAMINFO"
|
||||
" or frame header\n");
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
if (fi.samplerate == 0)
|
||||
fi.samplerate = s->flac_stream_info.samplerate;
|
||||
s->flac_stream_info.samplerate = s->avctx->sample_rate = fi.samplerate;
|
||||
|
||||
if (!s->got_streaminfo) {
|
||||
ret = allocate_buffers(s);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
s->got_streaminfo = 1;
|
||||
dump_headers(s->avctx, &s->flac_stream_info);
|
||||
}
|
||||
ff_flacdsp_init(&s->dsp, s->avctx->sample_fmt,
|
||||
s->flac_stream_info.channels, s->flac_stream_info.bps);
|
||||
|
||||
// dump_headers(s->avctx, &s->flac_stream_info);
|
||||
|
||||
/* subframes */
|
||||
for (i = 0; i < s->flac_stream_info.channels; i++) {
|
||||
if ((ret = decode_subframe(s, i)) < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
align_get_bits(gb);
|
||||
|
||||
/* frame footer */
|
||||
skip_bits(gb, 16); /* data crc */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flac_decode_frame(AVCodecContext *avctx, void *data,
|
||||
int *got_frame_ptr, AVPacket *avpkt)
|
||||
{
|
||||
AVFrame *frame = data;
|
||||
ThreadFrame tframe = { .f = data };
|
||||
const uint8_t *buf = avpkt->data;
|
||||
int buf_size = avpkt->size;
|
||||
FLACContext *s = avctx->priv_data;
|
||||
int bytes_read = 0;
|
||||
int ret;
|
||||
|
||||
*got_frame_ptr = 0;
|
||||
|
||||
if (s->flac_stream_info.max_framesize == 0) {
|
||||
s->flac_stream_info.max_framesize =
|
||||
ff_flac_get_max_frame_size(s->flac_stream_info.max_blocksize ? s->flac_stream_info.max_blocksize : FLAC_MAX_BLOCKSIZE,
|
||||
FLAC_MAX_CHANNELS, 32);
|
||||
}
|
||||
|
||||
if (buf_size > 5 && !memcmp(buf, "\177FLAC", 5)) {
|
||||
av_log(s->avctx, AV_LOG_DEBUG, "skipping flac header packet 1\n");
|
||||
return buf_size;
|
||||
}
|
||||
|
||||
if (buf_size > 0 && (*buf & 0x7F) == FLAC_METADATA_TYPE_VORBIS_COMMENT) {
|
||||
av_log(s->avctx, AV_LOG_DEBUG, "skipping vorbis comment\n");
|
||||
return buf_size;
|
||||
}
|
||||
|
||||
/* check that there is at least the smallest decodable amount of data.
|
||||
this amount corresponds to the smallest valid FLAC frame possible.
|
||||
FF F8 69 02 00 00 9A 00 00 34 46 */
|
||||
if (buf_size < FLAC_MIN_FRAME_SIZE)
|
||||
return buf_size;
|
||||
|
||||
/* check for inline header */
|
||||
if (AV_RB32(buf) == MKBETAG('f','L','a','C')) {
|
||||
if (!s->got_streaminfo && (ret = parse_streaminfo(s, buf, buf_size))) {
|
||||
av_log(s->avctx, AV_LOG_ERROR, "invalid header\n");
|
||||
return ret;
|
||||
}
|
||||
return get_metadata_size(buf, buf_size);
|
||||
}
|
||||
|
||||
/* decode frame */
|
||||
if ((ret = init_get_bits8(&s->gb, buf, buf_size)) < 0)
|
||||
return ret;
|
||||
if ((ret = decode_frame(s)) < 0) {
|
||||
av_log(s->avctx, AV_LOG_ERROR, "decode_frame() failed\n");
|
||||
return ret;
|
||||
}
|
||||
bytes_read = get_bits_count(&s->gb)/8;
|
||||
|
||||
if ((s->avctx->err_recognition & (AV_EF_CRCCHECK|AV_EF_COMPLIANT)) &&
|
||||
av_crc(av_crc_get_table(AV_CRC_16_ANSI),
|
||||
0, buf, bytes_read)) {
|
||||
av_log(s->avctx, AV_LOG_ERROR, "CRC error at PTS %"PRId64"\n", avpkt->pts);
|
||||
if (s->avctx->err_recognition & AV_EF_EXPLODE)
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
/* get output buffer */
|
||||
frame->nb_samples = s->blocksize;
|
||||
if ((ret = ff_thread_get_buffer(avctx, &tframe, 0)) < 0)
|
||||
return ret;
|
||||
|
||||
s->dsp.decorrelate[s->ch_mode](frame->data, s->decoded,
|
||||
s->flac_stream_info.channels,
|
||||
s->blocksize, s->sample_shift);
|
||||
|
||||
if (bytes_read > buf_size) {
|
||||
av_log(s->avctx, AV_LOG_ERROR, "overread: %d\n", bytes_read - buf_size);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
if (bytes_read < buf_size) {
|
||||
av_log(s->avctx, AV_LOG_DEBUG, "underread: %d orig size: %d\n",
|
||||
buf_size - bytes_read, buf_size);
|
||||
}
|
||||
|
||||
*got_frame_ptr = 1;
|
||||
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
#if HAVE_THREADS
|
||||
static int init_thread_copy(AVCodecContext *avctx)
|
||||
{
|
||||
FLACContext *s = avctx->priv_data;
|
||||
s->decoded_buffer = NULL;
|
||||
s->decoded_buffer_size = 0;
|
||||
s->avctx = avctx;
|
||||
if (s->flac_stream_info.max_blocksize)
|
||||
return allocate_buffers(s);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static av_cold int flac_decode_close(AVCodecContext *avctx)
|
||||
{
|
||||
FLACContext *s = avctx->priv_data;
|
||||
|
||||
av_freep(&s->decoded_buffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const AVOption options[] = {
|
||||
{ "use_buggy_lpc", "emulate old buggy lavc behavior", offsetof(FLACContext, buggy_lpc), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_AUDIO_PARAM },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
static const AVClass flac_decoder_class = {
|
||||
"FLAC decoder",
|
||||
av_default_item_name,
|
||||
options,
|
||||
LIBAVUTIL_VERSION_INT,
|
||||
};
|
||||
|
||||
AVCodec ff_flac_decoder = {
|
||||
.name = "flac",
|
||||
.long_name = NULL_IF_CONFIG_SMALL("FLAC (Free Lossless Audio Codec)"),
|
||||
.type = AVMEDIA_TYPE_AUDIO,
|
||||
.id = AV_CODEC_ID_FLAC,
|
||||
.priv_data_size = sizeof(FLACContext),
|
||||
.init = flac_decode_init,
|
||||
.close = flac_decode_close,
|
||||
.decode = flac_decode_frame,
|
||||
.init_thread_copy = ONLY_IF_THREADS_ENABLED(init_thread_copy),
|
||||
.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS,
|
||||
.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16,
|
||||
AV_SAMPLE_FMT_S16P,
|
||||
AV_SAMPLE_FMT_S32,
|
||||
AV_SAMPLE_FMT_S32P,
|
||||
AV_SAMPLE_FMT_NONE },
|
||||
.priv_class = &flac_decoder_class,
|
||||
};
|
130
media/ffvpx/libavcodec/flacdsp.c
Normal file
130
media/ffvpx/libavcodec/flacdsp.c
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Mans Rullgard <mans@mansr.com>
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "libavutil/attributes.h"
|
||||
#include "libavutil/samplefmt.h"
|
||||
#include "flacdsp.h"
|
||||
#include "config.h"
|
||||
|
||||
#define SAMPLE_SIZE 16
|
||||
#define PLANAR 0
|
||||
#include "flacdsp_template.c"
|
||||
#include "flacdsp_lpc_template.c"
|
||||
|
||||
#undef PLANAR
|
||||
#define PLANAR 1
|
||||
#include "flacdsp_template.c"
|
||||
|
||||
#undef SAMPLE_SIZE
|
||||
#undef PLANAR
|
||||
#define SAMPLE_SIZE 32
|
||||
#define PLANAR 0
|
||||
#include "flacdsp_template.c"
|
||||
#include "flacdsp_lpc_template.c"
|
||||
|
||||
#undef PLANAR
|
||||
#define PLANAR 1
|
||||
#include "flacdsp_template.c"
|
||||
|
||||
static void flac_lpc_16_c(int32_t *decoded, const int coeffs[32],
|
||||
int pred_order, int qlevel, int len)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = pred_order; i < len - 1; i += 2, decoded += 2) {
|
||||
int c = coeffs[0];
|
||||
int d = decoded[0];
|
||||
int s0 = 0, s1 = 0;
|
||||
for (j = 1; j < pred_order; j++) {
|
||||
s0 += c*d;
|
||||
d = decoded[j];
|
||||
s1 += c*d;
|
||||
c = coeffs[j];
|
||||
}
|
||||
s0 += c*d;
|
||||
d = decoded[j] += s0 >> qlevel;
|
||||
s1 += c*d;
|
||||
decoded[j + 1] += s1 >> qlevel;
|
||||
}
|
||||
if (i < len) {
|
||||
int sum = 0;
|
||||
for (j = 0; j < pred_order; j++)
|
||||
sum += coeffs[j] * decoded[j];
|
||||
decoded[j] += sum >> qlevel;
|
||||
}
|
||||
}
|
||||
|
||||
static void flac_lpc_32_c(int32_t *decoded, const int coeffs[32],
|
||||
int pred_order, int qlevel, int len)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = pred_order; i < len; i++, decoded++) {
|
||||
int64_t sum = 0;
|
||||
for (j = 0; j < pred_order; j++)
|
||||
sum += (int64_t)coeffs[j] * decoded[j];
|
||||
decoded[j] += sum >> qlevel;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
av_cold void ff_flacdsp_init(FLACDSPContext *c, enum AVSampleFormat fmt, int channels,
|
||||
int bps)
|
||||
{
|
||||
c->lpc16 = flac_lpc_16_c;
|
||||
c->lpc32 = flac_lpc_32_c;
|
||||
c->lpc16_encode = flac_lpc_encode_c_16;
|
||||
c->lpc32_encode = flac_lpc_encode_c_32;
|
||||
|
||||
switch (fmt) {
|
||||
case AV_SAMPLE_FMT_S32:
|
||||
c->decorrelate[0] = flac_decorrelate_indep_c_32;
|
||||
c->decorrelate[1] = flac_decorrelate_ls_c_32;
|
||||
c->decorrelate[2] = flac_decorrelate_rs_c_32;
|
||||
c->decorrelate[3] = flac_decorrelate_ms_c_32;
|
||||
break;
|
||||
|
||||
case AV_SAMPLE_FMT_S32P:
|
||||
c->decorrelate[0] = flac_decorrelate_indep_c_32p;
|
||||
c->decorrelate[1] = flac_decorrelate_ls_c_32p;
|
||||
c->decorrelate[2] = flac_decorrelate_rs_c_32p;
|
||||
c->decorrelate[3] = flac_decorrelate_ms_c_32p;
|
||||
break;
|
||||
|
||||
case AV_SAMPLE_FMT_S16:
|
||||
c->decorrelate[0] = flac_decorrelate_indep_c_16;
|
||||
c->decorrelate[1] = flac_decorrelate_ls_c_16;
|
||||
c->decorrelate[2] = flac_decorrelate_rs_c_16;
|
||||
c->decorrelate[3] = flac_decorrelate_ms_c_16;
|
||||
break;
|
||||
|
||||
case AV_SAMPLE_FMT_S16P:
|
||||
c->decorrelate[0] = flac_decorrelate_indep_c_16p;
|
||||
c->decorrelate[1] = flac_decorrelate_ls_c_16p;
|
||||
c->decorrelate[2] = flac_decorrelate_rs_c_16p;
|
||||
c->decorrelate[3] = flac_decorrelate_ms_c_16p;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ARCH_ARM)
|
||||
ff_flacdsp_init_arm(c, fmt, channels, bps);
|
||||
if (ARCH_X86)
|
||||
ff_flacdsp_init_x86(c, fmt, channels, bps);
|
||||
}
|
42
media/ffvpx/libavcodec/flacdsp.h
Normal file
42
media/ffvpx/libavcodec/flacdsp.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_FLACDSP_H
|
||||
#define AVCODEC_FLACDSP_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "libavutil/samplefmt.h"
|
||||
|
||||
typedef struct FLACDSPContext {
|
||||
void (*decorrelate[4])(uint8_t **out, int32_t **in, int channels,
|
||||
int len, int shift);
|
||||
void (*lpc16)(int32_t *samples, const int coeffs[32], int order,
|
||||
int qlevel, int len);
|
||||
void (*lpc32)(int32_t *samples, const int coeffs[32], int order,
|
||||
int qlevel, int len);
|
||||
void (*lpc16_encode)(int32_t *res, const int32_t *smp, int len, int order,
|
||||
const int32_t coefs[32], int shift);
|
||||
void (*lpc32_encode)(int32_t *res, const int32_t *smp, int len, int order,
|
||||
const int32_t coefs[32], int shift);
|
||||
} FLACDSPContext;
|
||||
|
||||
void ff_flacdsp_init(FLACDSPContext *c, enum AVSampleFormat fmt, int channels, int bps);
|
||||
void ff_flacdsp_init_arm(FLACDSPContext *c, enum AVSampleFormat fmt, int channels, int bps);
|
||||
void ff_flacdsp_init_x86(FLACDSPContext *c, enum AVSampleFormat fmt, int channels, int bps);
|
||||
|
||||
#endif /* AVCODEC_FLACDSP_H */
|
159
media/ffvpx/libavcodec/flacdsp_lpc_template.c
Normal file
159
media/ffvpx/libavcodec/flacdsp_lpc_template.c
Normal file
@ -0,0 +1,159 @@
|
||||
/*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "libavutil/avutil.h"
|
||||
#include "mathops.h"
|
||||
|
||||
#undef FUNC
|
||||
#undef sum_type
|
||||
#undef MUL
|
||||
#undef CLIP
|
||||
#undef FSUF
|
||||
|
||||
#define FUNC(n) AV_JOIN(n ## _, SAMPLE_SIZE)
|
||||
|
||||
#if SAMPLE_SIZE == 32
|
||||
# define sum_type int64_t
|
||||
# define MUL(a, b) MUL64(a, b)
|
||||
# define CLIP(x) av_clipl_int32(x)
|
||||
#else
|
||||
# define sum_type int32_t
|
||||
# define MUL(a, b) ((a) * (b))
|
||||
# define CLIP(x) (x)
|
||||
#endif
|
||||
|
||||
#define LPC1(x) { \
|
||||
int c = coefs[(x)-1]; \
|
||||
p0 += MUL(c, s); \
|
||||
s = smp[i-(x)+1]; \
|
||||
p1 += MUL(c, s); \
|
||||
}
|
||||
|
||||
static av_always_inline void FUNC(lpc_encode_unrolled)(int32_t *res,
|
||||
const int32_t *smp, int len, int order,
|
||||
const int32_t *coefs, int shift, int big)
|
||||
{
|
||||
int i;
|
||||
for (i = order; i < len; i += 2) {
|
||||
int s = smp[i-order];
|
||||
sum_type p0 = 0, p1 = 0;
|
||||
if (big) {
|
||||
switch (order) {
|
||||
case 32: LPC1(32)
|
||||
case 31: LPC1(31)
|
||||
case 30: LPC1(30)
|
||||
case 29: LPC1(29)
|
||||
case 28: LPC1(28)
|
||||
case 27: LPC1(27)
|
||||
case 26: LPC1(26)
|
||||
case 25: LPC1(25)
|
||||
case 24: LPC1(24)
|
||||
case 23: LPC1(23)
|
||||
case 22: LPC1(22)
|
||||
case 21: LPC1(21)
|
||||
case 20: LPC1(20)
|
||||
case 19: LPC1(19)
|
||||
case 18: LPC1(18)
|
||||
case 17: LPC1(17)
|
||||
case 16: LPC1(16)
|
||||
case 15: LPC1(15)
|
||||
case 14: LPC1(14)
|
||||
case 13: LPC1(13)
|
||||
case 12: LPC1(12)
|
||||
case 11: LPC1(11)
|
||||
case 10: LPC1(10)
|
||||
case 9: LPC1( 9)
|
||||
LPC1( 8)
|
||||
LPC1( 7)
|
||||
LPC1( 6)
|
||||
LPC1( 5)
|
||||
LPC1( 4)
|
||||
LPC1( 3)
|
||||
LPC1( 2)
|
||||
LPC1( 1)
|
||||
}
|
||||
} else {
|
||||
switch (order) {
|
||||
case 8: LPC1( 8)
|
||||
case 7: LPC1( 7)
|
||||
case 6: LPC1( 6)
|
||||
case 5: LPC1( 5)
|
||||
case 4: LPC1( 4)
|
||||
case 3: LPC1( 3)
|
||||
case 2: LPC1( 2)
|
||||
case 1: LPC1( 1)
|
||||
}
|
||||
}
|
||||
res[i ] = smp[i ] - CLIP(p0 >> shift);
|
||||
res[i+1] = smp[i+1] - CLIP(p1 >> shift);
|
||||
}
|
||||
}
|
||||
|
||||
static void FUNC(flac_lpc_encode_c)(int32_t *res, const int32_t *smp, int len,
|
||||
int order, const int32_t *coefs, int shift)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < order; i++)
|
||||
res[i] = smp[i];
|
||||
#if CONFIG_SMALL
|
||||
for (i = order; i < len; i += 2) {
|
||||
int j;
|
||||
int s = smp[i];
|
||||
sum_type p0 = 0, p1 = 0;
|
||||
for (j = 0; j < order; j++) {
|
||||
int c = coefs[j];
|
||||
p1 += MUL(c, s);
|
||||
s = smp[i-j-1];
|
||||
p0 += MUL(c, s);
|
||||
}
|
||||
res[i ] = smp[i ] - CLIP(p0 >> shift);
|
||||
res[i+1] = smp[i+1] - CLIP(p1 >> shift);
|
||||
}
|
||||
#else
|
||||
switch (order) {
|
||||
case 1: FUNC(lpc_encode_unrolled)(res, smp, len, 1, coefs, shift, 0); break;
|
||||
case 2: FUNC(lpc_encode_unrolled)(res, smp, len, 2, coefs, shift, 0); break;
|
||||
case 3: FUNC(lpc_encode_unrolled)(res, smp, len, 3, coefs, shift, 0); break;
|
||||
case 4: FUNC(lpc_encode_unrolled)(res, smp, len, 4, coefs, shift, 0); break;
|
||||
case 5: FUNC(lpc_encode_unrolled)(res, smp, len, 5, coefs, shift, 0); break;
|
||||
case 6: FUNC(lpc_encode_unrolled)(res, smp, len, 6, coefs, shift, 0); break;
|
||||
case 7: FUNC(lpc_encode_unrolled)(res, smp, len, 7, coefs, shift, 0); break;
|
||||
case 8: FUNC(lpc_encode_unrolled)(res, smp, len, 8, coefs, shift, 0); break;
|
||||
default: FUNC(lpc_encode_unrolled)(res, smp, len, order, coefs, shift, 1); break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Comment for clarity/de-obfuscation.
|
||||
*
|
||||
* for (int i = order; i < len; i++) {
|
||||
* int32_t p = 0;
|
||||
* for (int j = 0; j < order; j++) {
|
||||
* int c = coefs[j];
|
||||
* int s = smp[(i-1)-j];
|
||||
* p += c*s;
|
||||
* }
|
||||
* res[i] = smp[i] - (p >> shift);
|
||||
* }
|
||||
*
|
||||
* The CONFIG_SMALL code above simplifies to this, in the case of SAMPLE_SIZE
|
||||
* not being equal to 32 (at the present time that means for 16-bit audio). The
|
||||
* code above does 2 samples per iteration. Commit bfdd5bc (made all the way
|
||||
* back in 2007) says that way is faster.
|
||||
*/
|
103
media/ffvpx/libavcodec/flacdsp_template.c
Normal file
103
media/ffvpx/libavcodec/flacdsp_template.c
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Mans Rullgard <mans@mansr.com>
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "libavutil/avutil.h"
|
||||
|
||||
#undef FUNC
|
||||
#undef FSUF
|
||||
#undef sample
|
||||
#undef sample_type
|
||||
#undef OUT
|
||||
#undef S
|
||||
|
||||
#if SAMPLE_SIZE == 32
|
||||
# define sample_type int32_t
|
||||
#else
|
||||
# define sample_type int16_t
|
||||
#endif
|
||||
|
||||
#if PLANAR
|
||||
# define FSUF AV_JOIN(SAMPLE_SIZE, p)
|
||||
# define sample sample_type *
|
||||
# define OUT(n) n
|
||||
# define S(s, c, i) (s[c][i])
|
||||
#else
|
||||
# define FSUF SAMPLE_SIZE
|
||||
# define sample sample_type
|
||||
# define OUT(n) n[0]
|
||||
# define S(s, c, i) (*s++)
|
||||
#endif
|
||||
|
||||
#define FUNC(n) AV_JOIN(n ## _, FSUF)
|
||||
|
||||
static void FUNC(flac_decorrelate_indep_c)(uint8_t **out, int32_t **in,
|
||||
int channels, int len, int shift)
|
||||
{
|
||||
sample *samples = (sample *) OUT(out);
|
||||
int i, j;
|
||||
|
||||
for (j = 0; j < len; j++)
|
||||
for (i = 0; i < channels; i++)
|
||||
S(samples, i, j) = in[i][j] << shift;
|
||||
}
|
||||
|
||||
static void FUNC(flac_decorrelate_ls_c)(uint8_t **out, int32_t **in,
|
||||
int channels, int len, int shift)
|
||||
{
|
||||
sample *samples = (sample *) OUT(out);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
int a = in[0][i];
|
||||
int b = in[1][i];
|
||||
S(samples, 0, i) = a << shift;
|
||||
S(samples, 1, i) = (a - b) << shift;
|
||||
}
|
||||
}
|
||||
|
||||
static void FUNC(flac_decorrelate_rs_c)(uint8_t **out, int32_t **in,
|
||||
int channels, int len, int shift)
|
||||
{
|
||||
sample *samples = (sample *) OUT(out);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
int a = in[0][i];
|
||||
int b = in[1][i];
|
||||
S(samples, 0, i) = (a + b) << shift;
|
||||
S(samples, 1, i) = b << shift;
|
||||
}
|
||||
}
|
||||
|
||||
static void FUNC(flac_decorrelate_ms_c)(uint8_t **out, int32_t **in,
|
||||
int channels, int len, int shift)
|
||||
{
|
||||
sample *samples = (sample *) OUT(out);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
int a = in[0][i];
|
||||
int b = in[1][i];
|
||||
a -= b >> 1;
|
||||
S(samples, 0, i) = (a + b) << shift;
|
||||
S(samples, 1, i) = a << shift;
|
||||
}
|
||||
}
|
173
media/ffvpx/libavcodec/golomb.c
Normal file
173
media/ffvpx/libavcodec/golomb.c
Normal file
@ -0,0 +1,173 @@
|
||||
/*
|
||||
* exp golomb vlc stuff
|
||||
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief
|
||||
* exp golomb vlc stuff
|
||||
* @author Michael Niedermayer <michaelni@gmx.at>
|
||||
*/
|
||||
|
||||
#include "libavutil/common.h"
|
||||
|
||||
const uint8_t ff_golomb_vlc_len[512]={
|
||||
19,17,15,15,13,13,13,13,11,11,11,11,11,11,11,11,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
|
||||
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
||||
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
|
||||
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
|
||||
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
||||
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
||||
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
||||
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
|
||||
};
|
||||
|
||||
const uint8_t ff_ue_golomb_vlc_code[512]={
|
||||
32,32,32,32,32,32,32,32,31,32,32,32,32,32,32,32,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,
|
||||
7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9,10,10,10,10,11,11,11,11,12,12,12,12,13,13,13,13,14,14,14,14,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
const int8_t ff_se_golomb_vlc_code[512]={
|
||||
17, 17, 17, 17, 17, 17, 17, 17, 16, 17, 17, 17, 17, 17, 17, 17, 8, -8, 9, -9, 10,-10, 11,-11, 12,-12, 13,-13, 14,-14, 15,-15,
|
||||
4, 4, 4, 4, -4, -4, -4, -4, 5, 5, 5, 5, -5, -5, -5, -5, 6, 6, 6, 6, -6, -6, -6, -6, 7, 7, 7, 7, -7, -7, -7, -7,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
|
||||
const uint8_t ff_ue_golomb_len[256]={
|
||||
1, 3, 3, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,11,
|
||||
11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,13,
|
||||
13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
|
||||
13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,15,
|
||||
15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
|
||||
15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
|
||||
15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
|
||||
15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,17,
|
||||
};
|
||||
|
||||
const uint8_t ff_interleaved_golomb_vlc_len[256]={
|
||||
9,9,7,7,9,9,7,7,5,5,5,5,5,5,5,5,
|
||||
9,9,7,7,9,9,7,7,5,5,5,5,5,5,5,5,
|
||||
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
||||
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
||||
9,9,7,7,9,9,7,7,5,5,5,5,5,5,5,5,
|
||||
9,9,7,7,9,9,7,7,5,5,5,5,5,5,5,5,
|
||||
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
||||
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
};
|
||||
|
||||
const uint8_t ff_interleaved_ue_golomb_vlc_code[256]={
|
||||
15,16,7, 7, 17,18,8, 8, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
19,20,9, 9, 21,22,10,10,4, 4, 4, 4, 4, 4, 4, 4,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
23,24,11,11,25,26,12,12,5, 5, 5, 5, 5, 5, 5, 5,
|
||||
27,28,13,13,29,30,14,14,6, 6, 6, 6, 6, 6, 6, 6,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
const int8_t ff_interleaved_se_golomb_vlc_code[256]={
|
||||
8, -8, 4, 4, 9, -9, -4, -4, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
10,-10, 5, 5, 11,-11, -5, -5, -2, -2, -2, -2, -2, -2, -2, -2,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
12,-12, 6, 6, 13,-13, -6, -6, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
14,-14, 7, 7, 15,-15, -7, -7, -3, -3, -3, -3, -3, -3, -3, -3,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
const uint8_t ff_interleaved_dirac_golomb_vlc_code[256]={
|
||||
0, 1, 0, 0, 2, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
4, 5, 2, 2, 6, 7, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
8, 9, 4, 4, 10,11,5, 5, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
12,13,6, 6, 14,15,7, 7, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,};
|
579
media/ffvpx/libavcodec/golomb.h
Normal file
579
media/ffvpx/libavcodec/golomb.h
Normal file
@ -0,0 +1,579 @@
|
||||
/*
|
||||
* exp golomb vlc stuff
|
||||
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
|
||||
* Copyright (c) 2004 Alex Beregszaszi
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief
|
||||
* exp golomb vlc stuff
|
||||
* @author Michael Niedermayer <michaelni@gmx.at> and Alex Beregszaszi
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_GOLOMB_H
|
||||
#define AVCODEC_GOLOMB_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "get_bits.h"
|
||||
#include "put_bits.h"
|
||||
|
||||
#define INVALID_VLC 0x80000000
|
||||
|
||||
extern const uint8_t ff_golomb_vlc_len[512];
|
||||
extern const uint8_t ff_ue_golomb_vlc_code[512];
|
||||
extern const int8_t ff_se_golomb_vlc_code[512];
|
||||
extern const uint8_t ff_ue_golomb_len[256];
|
||||
|
||||
extern const uint8_t ff_interleaved_golomb_vlc_len[256];
|
||||
extern const uint8_t ff_interleaved_ue_golomb_vlc_code[256];
|
||||
extern const int8_t ff_interleaved_se_golomb_vlc_code[256];
|
||||
extern const uint8_t ff_interleaved_dirac_golomb_vlc_code[256];
|
||||
|
||||
/**
|
||||
* Read an unsigned Exp-Golomb code in the range 0 to 8190.
|
||||
*/
|
||||
static inline int get_ue_golomb(GetBitContext *gb)
|
||||
{
|
||||
unsigned int buf;
|
||||
|
||||
OPEN_READER(re, gb);
|
||||
UPDATE_CACHE(re, gb);
|
||||
buf = GET_CACHE(re, gb);
|
||||
|
||||
if (buf >= (1 << 27)) {
|
||||
buf >>= 32 - 9;
|
||||
LAST_SKIP_BITS(re, gb, ff_golomb_vlc_len[buf]);
|
||||
CLOSE_READER(re, gb);
|
||||
|
||||
return ff_ue_golomb_vlc_code[buf];
|
||||
} else {
|
||||
int log = 2 * av_log2(buf) - 31;
|
||||
LAST_SKIP_BITS(re, gb, 32 - log);
|
||||
CLOSE_READER(re, gb);
|
||||
if (log < 7) {
|
||||
av_log(NULL, AV_LOG_ERROR, "Invalid UE golomb code\n");
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
buf >>= log;
|
||||
buf--;
|
||||
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an unsigned Exp-Golomb code in the range 0 to UINT32_MAX-1.
|
||||
*/
|
||||
static inline unsigned get_ue_golomb_long(GetBitContext *gb)
|
||||
{
|
||||
unsigned buf, log;
|
||||
|
||||
buf = show_bits_long(gb, 32);
|
||||
log = 31 - av_log2(buf);
|
||||
skip_bits_long(gb, log);
|
||||
|
||||
return get_bits_long(gb, log + 1) - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* read unsigned exp golomb code, constraint to a max of 31.
|
||||
* the return value is undefined if the stored value exceeds 31.
|
||||
*/
|
||||
static inline int get_ue_golomb_31(GetBitContext *gb)
|
||||
{
|
||||
unsigned int buf;
|
||||
|
||||
OPEN_READER(re, gb);
|
||||
UPDATE_CACHE(re, gb);
|
||||
buf = GET_CACHE(re, gb);
|
||||
|
||||
buf >>= 32 - 9;
|
||||
LAST_SKIP_BITS(re, gb, ff_golomb_vlc_len[buf]);
|
||||
CLOSE_READER(re, gb);
|
||||
|
||||
return ff_ue_golomb_vlc_code[buf];
|
||||
}
|
||||
|
||||
static inline unsigned get_interleaved_ue_golomb(GetBitContext *gb)
|
||||
{
|
||||
uint32_t buf;
|
||||
|
||||
OPEN_READER(re, gb);
|
||||
UPDATE_CACHE(re, gb);
|
||||
buf = GET_CACHE(re, gb);
|
||||
|
||||
if (buf & 0xAA800000) {
|
||||
buf >>= 32 - 8;
|
||||
LAST_SKIP_BITS(re, gb, ff_interleaved_golomb_vlc_len[buf]);
|
||||
CLOSE_READER(re, gb);
|
||||
|
||||
return ff_interleaved_ue_golomb_vlc_code[buf];
|
||||
} else {
|
||||
unsigned ret = 1;
|
||||
|
||||
do {
|
||||
buf >>= 32 - 8;
|
||||
LAST_SKIP_BITS(re, gb,
|
||||
FFMIN(ff_interleaved_golomb_vlc_len[buf], 8));
|
||||
|
||||
if (ff_interleaved_golomb_vlc_len[buf] != 9) {
|
||||
ret <<= (ff_interleaved_golomb_vlc_len[buf] - 1) >> 1;
|
||||
ret |= ff_interleaved_dirac_golomb_vlc_code[buf];
|
||||
break;
|
||||
}
|
||||
ret = (ret << 4) | ff_interleaved_dirac_golomb_vlc_code[buf];
|
||||
UPDATE_CACHE(re, gb);
|
||||
buf = GET_CACHE(re, gb);
|
||||
} while (ret<0x8000000U && BITS_AVAILABLE(re, gb));
|
||||
|
||||
CLOSE_READER(re, gb);
|
||||
return ret - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* read unsigned truncated exp golomb code.
|
||||
*/
|
||||
static inline int get_te0_golomb(GetBitContext *gb, int range)
|
||||
{
|
||||
av_assert2(range >= 1);
|
||||
|
||||
if (range == 1)
|
||||
return 0;
|
||||
else if (range == 2)
|
||||
return get_bits1(gb) ^ 1;
|
||||
else
|
||||
return get_ue_golomb(gb);
|
||||
}
|
||||
|
||||
/**
|
||||
* read unsigned truncated exp golomb code.
|
||||
*/
|
||||
static inline int get_te_golomb(GetBitContext *gb, int range)
|
||||
{
|
||||
av_assert2(range >= 1);
|
||||
|
||||
if (range == 2)
|
||||
return get_bits1(gb) ^ 1;
|
||||
else
|
||||
return get_ue_golomb(gb);
|
||||
}
|
||||
|
||||
/**
|
||||
* read signed exp golomb code.
|
||||
*/
|
||||
static inline int get_se_golomb(GetBitContext *gb)
|
||||
{
|
||||
unsigned int buf;
|
||||
|
||||
OPEN_READER(re, gb);
|
||||
UPDATE_CACHE(re, gb);
|
||||
buf = GET_CACHE(re, gb);
|
||||
|
||||
if (buf >= (1 << 27)) {
|
||||
buf >>= 32 - 9;
|
||||
LAST_SKIP_BITS(re, gb, ff_golomb_vlc_len[buf]);
|
||||
CLOSE_READER(re, gb);
|
||||
|
||||
return ff_se_golomb_vlc_code[buf];
|
||||
} else {
|
||||
int log = av_log2(buf), sign;
|
||||
LAST_SKIP_BITS(re, gb, 31 - log);
|
||||
UPDATE_CACHE(re, gb);
|
||||
buf = GET_CACHE(re, gb);
|
||||
|
||||
buf >>= log;
|
||||
|
||||
LAST_SKIP_BITS(re, gb, 32 - log);
|
||||
CLOSE_READER(re, gb);
|
||||
|
||||
sign = -(buf & 1);
|
||||
buf = ((buf >> 1) ^ sign) - sign;
|
||||
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int get_se_golomb_long(GetBitContext *gb)
|
||||
{
|
||||
unsigned int buf = get_ue_golomb_long(gb);
|
||||
int sign = (buf & 1) - 1;
|
||||
return ((buf >> 1) ^ sign) + 1;
|
||||
}
|
||||
|
||||
static inline int get_interleaved_se_golomb(GetBitContext *gb)
|
||||
{
|
||||
unsigned int buf;
|
||||
|
||||
OPEN_READER(re, gb);
|
||||
UPDATE_CACHE(re, gb);
|
||||
buf = GET_CACHE(re, gb);
|
||||
|
||||
if (buf & 0xAA800000) {
|
||||
buf >>= 32 - 8;
|
||||
LAST_SKIP_BITS(re, gb, ff_interleaved_golomb_vlc_len[buf]);
|
||||
CLOSE_READER(re, gb);
|
||||
|
||||
return ff_interleaved_se_golomb_vlc_code[buf];
|
||||
} else {
|
||||
int log;
|
||||
LAST_SKIP_BITS(re, gb, 8);
|
||||
UPDATE_CACHE(re, gb);
|
||||
buf |= 1 | (GET_CACHE(re, gb) >> 8);
|
||||
|
||||
if ((buf & 0xAAAAAAAA) == 0)
|
||||
return INVALID_VLC;
|
||||
|
||||
for (log = 31; (buf & 0x80000000) == 0; log--)
|
||||
buf = (buf << 2) - ((buf << log) >> (log - 1)) + (buf >> 30);
|
||||
|
||||
LAST_SKIP_BITS(re, gb, 63 - 2 * log - 8);
|
||||
CLOSE_READER(re, gb);
|
||||
|
||||
return (signed) (((((buf << log) >> log) - 1) ^ -(buf & 0x1)) + 1) >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int dirac_get_se_golomb(GetBitContext *gb)
|
||||
{
|
||||
uint32_t ret = get_interleaved_ue_golomb(gb);
|
||||
|
||||
if (ret) {
|
||||
int sign = -get_bits1(gb);
|
||||
ret = (ret ^ sign) - sign;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* read unsigned golomb rice code (ffv1).
|
||||
*/
|
||||
static inline int get_ur_golomb(GetBitContext *gb, int k, int limit,
|
||||
int esc_len)
|
||||
{
|
||||
unsigned int buf;
|
||||
int log;
|
||||
|
||||
OPEN_READER(re, gb);
|
||||
UPDATE_CACHE(re, gb);
|
||||
buf = GET_CACHE(re, gb);
|
||||
|
||||
log = av_log2(buf);
|
||||
|
||||
if (log > 31 - limit) {
|
||||
buf >>= log - k;
|
||||
buf += (30U - log) << k;
|
||||
LAST_SKIP_BITS(re, gb, 32 + k - log);
|
||||
CLOSE_READER(re, gb);
|
||||
|
||||
return buf;
|
||||
} else {
|
||||
LAST_SKIP_BITS(re, gb, limit);
|
||||
UPDATE_CACHE(re, gb);
|
||||
|
||||
buf = SHOW_UBITS(re, gb, esc_len);
|
||||
|
||||
LAST_SKIP_BITS(re, gb, esc_len);
|
||||
CLOSE_READER(re, gb);
|
||||
|
||||
return buf + limit - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* read unsigned golomb rice code (jpegls).
|
||||
*/
|
||||
static inline int get_ur_golomb_jpegls(GetBitContext *gb, int k, int limit,
|
||||
int esc_len)
|
||||
{
|
||||
unsigned int buf;
|
||||
int log;
|
||||
|
||||
OPEN_READER(re, gb);
|
||||
UPDATE_CACHE(re, gb);
|
||||
buf = GET_CACHE(re, gb);
|
||||
|
||||
log = av_log2(buf);
|
||||
|
||||
if (log - k >= 32 - MIN_CACHE_BITS + (MIN_CACHE_BITS == 32) &&
|
||||
32 - log < limit) {
|
||||
buf >>= log - k;
|
||||
buf += (30U - log) << k;
|
||||
LAST_SKIP_BITS(re, gb, 32 + k - log);
|
||||
CLOSE_READER(re, gb);
|
||||
|
||||
return buf;
|
||||
} else {
|
||||
int i;
|
||||
for (i = 0; i < limit && SHOW_UBITS(re, gb, 1) == 0; i++) {
|
||||
if (gb->size_in_bits <= re_index)
|
||||
return -1;
|
||||
LAST_SKIP_BITS(re, gb, 1);
|
||||
UPDATE_CACHE(re, gb);
|
||||
}
|
||||
SKIP_BITS(re, gb, 1);
|
||||
|
||||
if (i < limit - 1) {
|
||||
if (k) {
|
||||
if (k > MIN_CACHE_BITS - 1) {
|
||||
buf = SHOW_UBITS(re, gb, 16) << (k-16);
|
||||
LAST_SKIP_BITS(re, gb, 16);
|
||||
UPDATE_CACHE(re, gb);
|
||||
buf |= SHOW_UBITS(re, gb, k-16);
|
||||
LAST_SKIP_BITS(re, gb, k-16);
|
||||
} else {
|
||||
buf = SHOW_UBITS(re, gb, k);
|
||||
LAST_SKIP_BITS(re, gb, k);
|
||||
}
|
||||
} else {
|
||||
buf = 0;
|
||||
}
|
||||
|
||||
CLOSE_READER(re, gb);
|
||||
return buf + (i << k);
|
||||
} else if (i == limit - 1) {
|
||||
buf = SHOW_UBITS(re, gb, esc_len);
|
||||
LAST_SKIP_BITS(re, gb, esc_len);
|
||||
CLOSE_READER(re, gb);
|
||||
|
||||
return buf + 1;
|
||||
} else
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* read signed golomb rice code (ffv1).
|
||||
*/
|
||||
static inline int get_sr_golomb(GetBitContext *gb, int k, int limit,
|
||||
int esc_len)
|
||||
{
|
||||
unsigned v = get_ur_golomb(gb, k, limit, esc_len);
|
||||
return (v >> 1) ^ -(v & 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* read signed golomb rice code (flac).
|
||||
*/
|
||||
static inline int get_sr_golomb_flac(GetBitContext *gb, int k, int limit,
|
||||
int esc_len)
|
||||
{
|
||||
unsigned v = get_ur_golomb_jpegls(gb, k, limit, esc_len);
|
||||
return (v >> 1) ^ -(v & 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* read unsigned golomb rice code (shorten).
|
||||
*/
|
||||
static inline unsigned int get_ur_golomb_shorten(GetBitContext *gb, int k)
|
||||
{
|
||||
return get_ur_golomb_jpegls(gb, k, INT_MAX, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* read signed golomb rice code (shorten).
|
||||
*/
|
||||
static inline int get_sr_golomb_shorten(GetBitContext *gb, int k)
|
||||
{
|
||||
int uvar = get_ur_golomb_jpegls(gb, k + 1, INT_MAX, 0);
|
||||
return (uvar >> 1) ^ -(uvar & 1);
|
||||
}
|
||||
|
||||
#ifdef TRACE
|
||||
|
||||
static inline int get_ue(GetBitContext *s, const char *file, const char *func,
|
||||
int line)
|
||||
{
|
||||
int show = show_bits(s, 24);
|
||||
int pos = get_bits_count(s);
|
||||
int i = get_ue_golomb(s);
|
||||
int len = get_bits_count(s) - pos;
|
||||
int bits = show >> (24 - len);
|
||||
|
||||
av_log(NULL, AV_LOG_DEBUG, "%5d %2d %3d ue @%5d in %s %s:%d\n",
|
||||
bits, len, i, pos, file, func, line);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static inline int get_se(GetBitContext *s, const char *file, const char *func,
|
||||
int line)
|
||||
{
|
||||
int show = show_bits(s, 24);
|
||||
int pos = get_bits_count(s);
|
||||
int i = get_se_golomb(s);
|
||||
int len = get_bits_count(s) - pos;
|
||||
int bits = show >> (24 - len);
|
||||
|
||||
av_log(NULL, AV_LOG_DEBUG, "%5d %2d %3d se @%5d in %s %s:%d\n",
|
||||
bits, len, i, pos, file, func, line);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static inline int get_te(GetBitContext *s, int r, char *file, const char *func,
|
||||
int line)
|
||||
{
|
||||
int show = show_bits(s, 24);
|
||||
int pos = get_bits_count(s);
|
||||
int i = get_te0_golomb(s, r);
|
||||
int len = get_bits_count(s) - pos;
|
||||
int bits = show >> (24 - len);
|
||||
|
||||
av_log(NULL, AV_LOG_DEBUG, "%5d %2d %3d te @%5d in %s %s:%d\n",
|
||||
bits, len, i, pos, file, func, line);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
#define get_ue_golomb(a) get_ue(a, __FILE__, __PRETTY_FUNCTION__, __LINE__)
|
||||
#define get_se_golomb(a) get_se(a, __FILE__, __PRETTY_FUNCTION__, __LINE__)
|
||||
#define get_te_golomb(a, r) get_te(a, r, __FILE__, __PRETTY_FUNCTION__, __LINE__)
|
||||
#define get_te0_golomb(a, r) get_te(a, r, __FILE__, __PRETTY_FUNCTION__, __LINE__)
|
||||
|
||||
#endif /* TRACE */
|
||||
|
||||
/**
|
||||
* write unsigned exp golomb code.
|
||||
*/
|
||||
static inline void set_ue_golomb(PutBitContext *pb, int i)
|
||||
{
|
||||
av_assert2(i >= 0);
|
||||
|
||||
if (i < 256)
|
||||
put_bits(pb, ff_ue_golomb_len[i], i + 1);
|
||||
else {
|
||||
int e = av_log2(i + 1);
|
||||
put_bits(pb, 2 * e + 1, i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* write truncated unsigned exp golomb code.
|
||||
*/
|
||||
static inline void set_te_golomb(PutBitContext *pb, int i, int range)
|
||||
{
|
||||
av_assert2(range >= 1);
|
||||
av_assert2(i <= range);
|
||||
|
||||
if (range == 2)
|
||||
put_bits(pb, 1, i ^ 1);
|
||||
else
|
||||
set_ue_golomb(pb, i);
|
||||
}
|
||||
|
||||
/**
|
||||
* write signed exp golomb code. 16 bits at most.
|
||||
*/
|
||||
static inline void set_se_golomb(PutBitContext *pb, int i)
|
||||
{
|
||||
#if 0
|
||||
if (i <= 0)
|
||||
i = -2 * i;
|
||||
else
|
||||
i = 2 * i - 1;
|
||||
#elif 1
|
||||
i = 2 * i - 1;
|
||||
if (i < 0)
|
||||
i ^= -1; //FIXME check if gcc does the right thing
|
||||
#else
|
||||
i = 2 * i - 1;
|
||||
i ^= (i >> 31);
|
||||
#endif
|
||||
set_ue_golomb(pb, i);
|
||||
}
|
||||
|
||||
/**
|
||||
* write unsigned golomb rice code (ffv1).
|
||||
*/
|
||||
static inline void set_ur_golomb(PutBitContext *pb, int i, int k, int limit,
|
||||
int esc_len)
|
||||
{
|
||||
int e;
|
||||
|
||||
av_assert2(i >= 0);
|
||||
|
||||
e = i >> k;
|
||||
if (e < limit)
|
||||
put_bits(pb, e + k + 1, (1 << k) + av_mod_uintp2(i, k));
|
||||
else
|
||||
put_bits(pb, limit + esc_len, i - limit + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* write unsigned golomb rice code (jpegls).
|
||||
*/
|
||||
static inline void set_ur_golomb_jpegls(PutBitContext *pb, int i, int k,
|
||||
int limit, int esc_len)
|
||||
{
|
||||
int e;
|
||||
|
||||
av_assert2(i >= 0);
|
||||
|
||||
e = (i >> k) + 1;
|
||||
if (e < limit) {
|
||||
while (e > 31) {
|
||||
put_bits(pb, 31, 0);
|
||||
e -= 31;
|
||||
}
|
||||
put_bits(pb, e, 1);
|
||||
if (k)
|
||||
put_sbits(pb, k, i);
|
||||
} else {
|
||||
while (limit > 31) {
|
||||
put_bits(pb, 31, 0);
|
||||
limit -= 31;
|
||||
}
|
||||
put_bits(pb, limit, 1);
|
||||
put_bits(pb, esc_len, i - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* write signed golomb rice code (ffv1).
|
||||
*/
|
||||
static inline void set_sr_golomb(PutBitContext *pb, int i, int k, int limit,
|
||||
int esc_len)
|
||||
{
|
||||
int v;
|
||||
|
||||
v = -2 * i - 1;
|
||||
v ^= (v >> 31);
|
||||
|
||||
set_ur_golomb(pb, v, k, limit, esc_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* write signed golomb rice code (flac).
|
||||
*/
|
||||
static inline void set_sr_golomb_flac(PutBitContext *pb, int i, int k,
|
||||
int limit, int esc_len)
|
||||
{
|
||||
int v;
|
||||
|
||||
v = -2 * i - 1;
|
||||
v ^= (v >> 31);
|
||||
|
||||
set_ur_golomb_jpegls(pb, v, k, limit, esc_len);
|
||||
}
|
||||
|
||||
#endif /* AVCODEC_GOLOMB_H */
|
@ -18,6 +18,12 @@ SOURCES += [
|
||||
'bitstream.c',
|
||||
'codec_desc.c',
|
||||
'dummy_funcs.c',
|
||||
'flac.c',
|
||||
'flac_parser.c',
|
||||
'flacdata.c',
|
||||
'flacdec.c',
|
||||
'flacdsp.c',
|
||||
'golomb.c',
|
||||
'h264pred.c',
|
||||
'imgconvert.c',
|
||||
'log2_tab.c',
|
||||
|
56
media/ffvpx/libavcodec/unary.h
Normal file
56
media/ffvpx/libavcodec/unary.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_UNARY_H
|
||||
#define AVCODEC_UNARY_H
|
||||
|
||||
#include "get_bits.h"
|
||||
|
||||
/**
|
||||
* Get unary code of limited length
|
||||
* @param gb GetBitContext
|
||||
* @param[in] stop The bitstop value (unary code of 1's or 0's)
|
||||
* @param[in] len Maximum length
|
||||
* @return Unary length/index
|
||||
*/
|
||||
static inline int get_unary(GetBitContext *gb, int stop, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < len && get_bits1(gb) != stop; i++);
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get unary code terminated by a 0 with a maximum length of 33
|
||||
* @param gb GetBitContext
|
||||
* @return Unary length/index
|
||||
*/
|
||||
static inline int get_unary_0_33(GetBitContext *gb)
|
||||
{
|
||||
return get_unary(gb, 0, 33);
|
||||
}
|
||||
|
||||
static inline int get_unary_0_9(GetBitContext *gb)
|
||||
{
|
||||
return get_unary(gb, 0, 9);
|
||||
}
|
||||
|
||||
#endif /* AVCODEC_UNARY_H */
|
313
media/ffvpx/libavcodec/x86/flacdsp.asm
Normal file
313
media/ffvpx/libavcodec/x86/flacdsp.asm
Normal file
@ -0,0 +1,313 @@
|
||||
;******************************************************************************
|
||||
;* FLAC DSP SIMD optimizations
|
||||
;*
|
||||
;* Copyright (C) 2014 Loren Merritt
|
||||
;* Copyright (C) 2014 James Almer
|
||||
;*
|
||||
;* This file is part of FFmpeg.
|
||||
;*
|
||||
;* FFmpeg is free software; you can redistribute it and/or
|
||||
;* modify it under the terms of the GNU Lesser General Public
|
||||
;* License as published by the Free Software Foundation; either
|
||||
;* version 2.1 of the License, or (at your option) any later version.
|
||||
;*
|
||||
;* FFmpeg is distributed in the hope that it will be useful,
|
||||
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
;* Lesser General Public License for more details.
|
||||
;*
|
||||
;* You should have received a copy of the GNU Lesser General Public
|
||||
;* License along with FFmpeg; if not, write to the Free Software
|
||||
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
;******************************************************************************
|
||||
|
||||
%include "libavutil/x86/x86util.asm"
|
||||
|
||||
SECTION .text
|
||||
|
||||
%macro PMACSDQL 5
|
||||
%if cpuflag(xop)
|
||||
pmacsdql %1, %2, %3, %1
|
||||
%else
|
||||
pmuldq %2, %3
|
||||
paddq %1, %2
|
||||
%endif
|
||||
%endmacro
|
||||
|
||||
%macro LPC_32 1
|
||||
INIT_XMM %1
|
||||
cglobal flac_lpc_32, 5,6,5, decoded, coeffs, pred_order, qlevel, len, j
|
||||
sub lend, pred_orderd
|
||||
jle .ret
|
||||
lea decodedq, [decodedq+pred_orderq*4-8]
|
||||
lea coeffsq, [coeffsq+pred_orderq*4]
|
||||
neg pred_orderq
|
||||
movd m4, qlevelm
|
||||
ALIGN 16
|
||||
.loop_sample:
|
||||
movd m0, [decodedq+pred_orderq*4+8]
|
||||
add decodedq, 8
|
||||
movd m1, [coeffsq+pred_orderq*4]
|
||||
pxor m2, m2
|
||||
pxor m3, m3
|
||||
lea jq, [pred_orderq+1]
|
||||
test jq, jq
|
||||
jz .end_order
|
||||
.loop_order:
|
||||
PMACSDQL m2, m0, m1, m2, m0
|
||||
movd m0, [decodedq+jq*4]
|
||||
PMACSDQL m3, m1, m0, m3, m1
|
||||
movd m1, [coeffsq+jq*4]
|
||||
inc jq
|
||||
jl .loop_order
|
||||
.end_order:
|
||||
PMACSDQL m2, m0, m1, m2, m0
|
||||
psrlq m2, m4
|
||||
movd m0, [decodedq]
|
||||
paddd m0, m2
|
||||
movd [decodedq], m0
|
||||
sub lend, 2
|
||||
jl .ret
|
||||
PMACSDQL m3, m1, m0, m3, m1
|
||||
psrlq m3, m4
|
||||
movd m1, [decodedq+4]
|
||||
paddd m1, m3
|
||||
movd [decodedq+4], m1
|
||||
jg .loop_sample
|
||||
.ret:
|
||||
REP_RET
|
||||
%endmacro
|
||||
|
||||
%if HAVE_XOP_EXTERNAL
|
||||
LPC_32 xop
|
||||
%endif
|
||||
LPC_32 sse4
|
||||
|
||||
;----------------------------------------------------------------------------------
|
||||
;void ff_flac_decorrelate_[lrm]s_16_sse2(uint8_t **out, int32_t **in, int channels,
|
||||
; int len, int shift);
|
||||
;----------------------------------------------------------------------------------
|
||||
%macro FLAC_DECORRELATE_16 3-4
|
||||
cglobal flac_decorrelate_%1_16, 2, 4, 4, out, in0, in1, len
|
||||
%if ARCH_X86_32
|
||||
mov lend, lenm
|
||||
%endif
|
||||
movd m3, r4m
|
||||
shl lend, 2
|
||||
mov in1q, [in0q + gprsize]
|
||||
mov in0q, [in0q]
|
||||
mov outq, [outq]
|
||||
add in1q, lenq
|
||||
add in0q, lenq
|
||||
add outq, lenq
|
||||
neg lenq
|
||||
|
||||
align 16
|
||||
.loop:
|
||||
mova m0, [in0q + lenq]
|
||||
mova m1, [in1q + lenq]
|
||||
%ifidn %1, ms
|
||||
psrad m2, m1, 1
|
||||
psubd m0, m2
|
||||
%endif
|
||||
%ifnidn %1, indep2
|
||||
p%4d m2, m0, m1
|
||||
%endif
|
||||
packssdw m%2, m%2
|
||||
packssdw m%3, m%3
|
||||
punpcklwd m%2, m%3
|
||||
psllw m%2, m3
|
||||
mova [outq + lenq], m%2
|
||||
add lenq, 16
|
||||
jl .loop
|
||||
REP_RET
|
||||
%endmacro
|
||||
|
||||
INIT_XMM sse2
|
||||
FLAC_DECORRELATE_16 ls, 0, 2, sub
|
||||
FLAC_DECORRELATE_16 rs, 2, 1, add
|
||||
FLAC_DECORRELATE_16 ms, 2, 0, add
|
||||
|
||||
;----------------------------------------------------------------------------------
|
||||
;void ff_flac_decorrelate_[lrm]s_32_sse2(uint8_t **out, int32_t **in, int channels,
|
||||
; int len, int shift);
|
||||
;----------------------------------------------------------------------------------
|
||||
%macro FLAC_DECORRELATE_32 5
|
||||
cglobal flac_decorrelate_%1_32, 2, 4, 4, out, in0, in1, len
|
||||
%if ARCH_X86_32
|
||||
mov lend, lenm
|
||||
%endif
|
||||
movd m3, r4m
|
||||
mov in1q, [in0q + gprsize]
|
||||
mov in0q, [in0q]
|
||||
mov outq, [outq]
|
||||
sub in1q, in0q
|
||||
|
||||
align 16
|
||||
.loop:
|
||||
mova m0, [in0q]
|
||||
mova m1, [in0q + in1q]
|
||||
%ifidn %1, ms
|
||||
psrad m2, m1, 1
|
||||
psubd m0, m2
|
||||
%endif
|
||||
p%5d m2, m0, m1
|
||||
pslld m%2, m3
|
||||
pslld m%3, m3
|
||||
|
||||
SBUTTERFLY dq, %2, %3, %4
|
||||
|
||||
mova [outq ], m%2
|
||||
mova [outq + mmsize], m%3
|
||||
|
||||
add in0q, mmsize
|
||||
add outq, mmsize*2
|
||||
sub lend, mmsize/4
|
||||
jg .loop
|
||||
REP_RET
|
||||
%endmacro
|
||||
|
||||
INIT_XMM sse2
|
||||
FLAC_DECORRELATE_32 ls, 0, 2, 1, sub
|
||||
FLAC_DECORRELATE_32 rs, 2, 1, 0, add
|
||||
FLAC_DECORRELATE_32 ms, 2, 0, 1, add
|
||||
|
||||
;-----------------------------------------------------------------------------------------
|
||||
;void ff_flac_decorrelate_indep<ch>_<bps>_<opt>(uint8_t **out, int32_t **in, int channels,
|
||||
; int len, int shift);
|
||||
;-----------------------------------------------------------------------------------------
|
||||
;%1 = bps
|
||||
;%2 = channels
|
||||
;%3 = last xmm reg used
|
||||
;%4 = word/dword (shift instruction)
|
||||
%macro FLAC_DECORRELATE_INDEP 4
|
||||
%define REPCOUNT %2/(32/%1) ; 16bits = channels / 2; 32bits = channels
|
||||
cglobal flac_decorrelate_indep%2_%1, 2, %2+2, %3+1, out, in0, in1, len, in2, in3, in4, in5, in6, in7
|
||||
%if ARCH_X86_32
|
||||
%if %2 == 6
|
||||
DEFINE_ARGS out, in0, in1, in2, in3, in4, in5
|
||||
%define lend dword r3m
|
||||
%else
|
||||
mov lend, lenm
|
||||
%endif
|
||||
%endif
|
||||
movd m%3, r4m
|
||||
|
||||
%assign %%i 1
|
||||
%rep %2-1
|
||||
mov in %+ %%i %+ q, [in0q+%%i*gprsize]
|
||||
%assign %%i %%i+1
|
||||
%endrep
|
||||
|
||||
mov in0q, [in0q]
|
||||
mov outq, [outq]
|
||||
|
||||
%assign %%i 1
|
||||
%rep %2-1
|
||||
sub in %+ %%i %+ q, in0q
|
||||
%assign %%i %%i+1
|
||||
%endrep
|
||||
|
||||
align 16
|
||||
.loop:
|
||||
mova m0, [in0q]
|
||||
|
||||
%assign %%i 1
|
||||
%rep REPCOUNT-1
|
||||
mova m %+ %%i, [in0q + in %+ %%i %+ q]
|
||||
%assign %%i %%i+1
|
||||
%endrep
|
||||
|
||||
%if %1 == 32
|
||||
|
||||
%if %2 == 8
|
||||
TRANSPOSE8x4D 0, 1, 2, 3, 4, 5, 6, 7, 8
|
||||
%elif %2 == 6
|
||||
SBUTTERFLY dq, 0, 1, 6
|
||||
SBUTTERFLY dq, 2, 3, 6
|
||||
SBUTTERFLY dq, 4, 5, 6
|
||||
|
||||
punpcklqdq m6, m0, m2
|
||||
punpckhqdq m2, m4
|
||||
shufps m4, m0, 0xe4
|
||||
punpcklqdq m0, m1, m3
|
||||
punpckhqdq m3, m5
|
||||
shufps m5, m1, 0xe4
|
||||
SWAP 0,6,1,4,5,3
|
||||
%elif %2 == 4
|
||||
TRANSPOSE4x4D 0, 1, 2, 3, 4
|
||||
%else ; %2 == 2
|
||||
SBUTTERFLY dq, 0, 1, 2
|
||||
%endif
|
||||
|
||||
%else ; %1 == 16
|
||||
|
||||
%if %2 == 8
|
||||
packssdw m0, [in0q + in4q]
|
||||
packssdw m1, [in0q + in5q]
|
||||
packssdw m2, [in0q + in6q]
|
||||
packssdw m3, [in0q + in7q]
|
||||
TRANSPOSE2x4x4W 0, 1, 2, 3, 4
|
||||
%elif %2 == 6
|
||||
packssdw m0, [in0q + in3q]
|
||||
packssdw m1, [in0q + in4q]
|
||||
packssdw m2, [in0q + in5q]
|
||||
pshufd m3, m0, q1032
|
||||
punpcklwd m0, m1
|
||||
punpckhwd m1, m2
|
||||
punpcklwd m2, m3
|
||||
|
||||
shufps m3, m0, m2, q2020
|
||||
shufps m0, m1, q2031
|
||||
shufps m2, m1, q3131
|
||||
shufps m1, m2, m3, q3120
|
||||
shufps m3, m0, q0220
|
||||
shufps m0, m2, q3113
|
||||
SWAP 2, 0, 3
|
||||
%else ; %2 == 4
|
||||
packssdw m0, [in0q + in2q]
|
||||
packssdw m1, [in0q + in3q]
|
||||
SBUTTERFLY wd, 0, 1, 2
|
||||
SBUTTERFLY dq, 0, 1, 2
|
||||
%endif
|
||||
|
||||
%endif
|
||||
|
||||
%assign %%i 0
|
||||
%rep REPCOUNT
|
||||
psll%4 m %+ %%i, m%3
|
||||
%assign %%i %%i+1
|
||||
%endrep
|
||||
|
||||
%assign %%i 0
|
||||
%rep REPCOUNT
|
||||
mova [outq + %%i*mmsize], m %+ %%i
|
||||
%assign %%i %%i+1
|
||||
%endrep
|
||||
|
||||
add in0q, mmsize
|
||||
add outq, mmsize*REPCOUNT
|
||||
sub lend, mmsize/4
|
||||
jg .loop
|
||||
REP_RET
|
||||
%endmacro
|
||||
|
||||
INIT_XMM sse2
|
||||
FLAC_DECORRELATE_16 indep2, 0, 1 ; Reuse stereo 16bits macro
|
||||
FLAC_DECORRELATE_INDEP 32, 2, 3, d
|
||||
FLAC_DECORRELATE_INDEP 16, 4, 3, w
|
||||
FLAC_DECORRELATE_INDEP 32, 4, 5, d
|
||||
FLAC_DECORRELATE_INDEP 16, 6, 4, w
|
||||
FLAC_DECORRELATE_INDEP 32, 6, 7, d
|
||||
%if ARCH_X86_64
|
||||
FLAC_DECORRELATE_INDEP 16, 8, 5, w
|
||||
FLAC_DECORRELATE_INDEP 32, 8, 9, d
|
||||
%endif
|
||||
|
||||
INIT_XMM avx
|
||||
FLAC_DECORRELATE_INDEP 32, 4, 5, d
|
||||
FLAC_DECORRELATE_INDEP 32, 6, 7, d
|
||||
%if ARCH_X86_64
|
||||
FLAC_DECORRELATE_INDEP 16, 8, 5, w
|
||||
FLAC_DECORRELATE_INDEP 32, 8, 9, d
|
||||
%endif
|
115
media/ffvpx/libavcodec/x86/flacdsp_init.c
Normal file
115
media/ffvpx/libavcodec/x86/flacdsp_init.c
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 2014 James Almer
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "libavcodec/flacdsp.h"
|
||||
#include "libavutil/x86/cpu.h"
|
||||
#include "config.h"
|
||||
|
||||
void ff_flac_lpc_32_sse4(int32_t *samples, const int coeffs[32], int order,
|
||||
int qlevel, int len);
|
||||
void ff_flac_lpc_32_xop(int32_t *samples, const int coeffs[32], int order,
|
||||
int qlevel, int len);
|
||||
|
||||
void ff_flac_enc_lpc_16_sse4(int32_t *, const int32_t *, int, int, const int32_t *,int);
|
||||
|
||||
#define DECORRELATE_FUNCS(fmt, opt) \
|
||||
void ff_flac_decorrelate_ls_##fmt##_##opt(uint8_t **out, int32_t **in, int channels, \
|
||||
int len, int shift); \
|
||||
void ff_flac_decorrelate_rs_##fmt##_##opt(uint8_t **out, int32_t **in, int channels, \
|
||||
int len, int shift); \
|
||||
void ff_flac_decorrelate_ms_##fmt##_##opt(uint8_t **out, int32_t **in, int channels, \
|
||||
int len, int shift); \
|
||||
void ff_flac_decorrelate_indep2_##fmt##_##opt(uint8_t **out, int32_t **in, int channels, \
|
||||
int len, int shift); \
|
||||
void ff_flac_decorrelate_indep4_##fmt##_##opt(uint8_t **out, int32_t **in, int channels, \
|
||||
int len, int shift); \
|
||||
void ff_flac_decorrelate_indep6_##fmt##_##opt(uint8_t **out, int32_t **in, int channels, \
|
||||
int len, int shift); \
|
||||
void ff_flac_decorrelate_indep8_##fmt##_##opt(uint8_t **out, int32_t **in, int channels, \
|
||||
int len, int shift)
|
||||
|
||||
DECORRELATE_FUNCS(16, sse2);
|
||||
DECORRELATE_FUNCS(16, avx);
|
||||
DECORRELATE_FUNCS(32, sse2);
|
||||
DECORRELATE_FUNCS(32, avx);
|
||||
|
||||
av_cold void ff_flacdsp_init_x86(FLACDSPContext *c, enum AVSampleFormat fmt, int channels,
|
||||
int bps)
|
||||
{
|
||||
#if HAVE_YASM
|
||||
int cpu_flags = av_get_cpu_flags();
|
||||
|
||||
#if CONFIG_FLAC_DECODER
|
||||
if (EXTERNAL_SSE2(cpu_flags)) {
|
||||
if (fmt == AV_SAMPLE_FMT_S16) {
|
||||
if (channels == 2)
|
||||
c->decorrelate[0] = ff_flac_decorrelate_indep2_16_sse2;
|
||||
else if (channels == 4)
|
||||
c->decorrelate[0] = ff_flac_decorrelate_indep4_16_sse2;
|
||||
else if (channels == 6)
|
||||
c->decorrelate[0] = ff_flac_decorrelate_indep6_16_sse2;
|
||||
else if (ARCH_X86_64 && channels == 8)
|
||||
c->decorrelate[0] = ff_flac_decorrelate_indep8_16_sse2;
|
||||
c->decorrelate[1] = ff_flac_decorrelate_ls_16_sse2;
|
||||
c->decorrelate[2] = ff_flac_decorrelate_rs_16_sse2;
|
||||
c->decorrelate[3] = ff_flac_decorrelate_ms_16_sse2;
|
||||
} else if (fmt == AV_SAMPLE_FMT_S32) {
|
||||
if (channels == 2)
|
||||
c->decorrelate[0] = ff_flac_decorrelate_indep2_32_sse2;
|
||||
else if (channels == 4)
|
||||
c->decorrelate[0] = ff_flac_decorrelate_indep4_32_sse2;
|
||||
else if (channels == 6)
|
||||
c->decorrelate[0] = ff_flac_decorrelate_indep6_32_sse2;
|
||||
else if (ARCH_X86_64 && channels == 8)
|
||||
c->decorrelate[0] = ff_flac_decorrelate_indep8_32_sse2;
|
||||
c->decorrelate[1] = ff_flac_decorrelate_ls_32_sse2;
|
||||
c->decorrelate[2] = ff_flac_decorrelate_rs_32_sse2;
|
||||
c->decorrelate[3] = ff_flac_decorrelate_ms_32_sse2;
|
||||
}
|
||||
}
|
||||
if (EXTERNAL_SSE4(cpu_flags)) {
|
||||
c->lpc32 = ff_flac_lpc_32_sse4;
|
||||
}
|
||||
if (EXTERNAL_AVX(cpu_flags)) {
|
||||
if (fmt == AV_SAMPLE_FMT_S16) {
|
||||
if (ARCH_X86_64 && channels == 8)
|
||||
c->decorrelate[0] = ff_flac_decorrelate_indep8_16_avx;
|
||||
} else if (fmt == AV_SAMPLE_FMT_S32) {
|
||||
if (channels == 4)
|
||||
c->decorrelate[0] = ff_flac_decorrelate_indep4_32_avx;
|
||||
else if (channels == 6)
|
||||
c->decorrelate[0] = ff_flac_decorrelate_indep6_32_avx;
|
||||
else if (ARCH_X86_64 && channels == 8)
|
||||
c->decorrelate[0] = ff_flac_decorrelate_indep8_32_avx;
|
||||
}
|
||||
}
|
||||
if (EXTERNAL_XOP(cpu_flags)) {
|
||||
c->lpc32 = ff_flac_lpc_32_xop;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_FLAC_ENCODER
|
||||
if (EXTERNAL_SSE4(cpu_flags)) {
|
||||
if (CONFIG_GPL)
|
||||
c->lpc16_encode = ff_flac_enc_lpc_16_sse4;
|
||||
}
|
||||
#endif
|
||||
#endif /* HAVE_YASM */
|
||||
}
|
@ -6,6 +6,8 @@
|
||||
|
||||
SOURCES += [
|
||||
'constants.c',
|
||||
'flacdsp.asm',
|
||||
'flacdsp_init.c',
|
||||
'h264_intrapred.asm',
|
||||
'h264_intrapred_10bit.asm',
|
||||
'h264_intrapred_init.c',
|
||||
|
104
media/libstagefright/binding/BitReader.cpp
Normal file
104
media/libstagefright/binding/BitReader.cpp
Normal file
@ -0,0 +1,104 @@
|
||||
/* 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 "mp4_demuxer/BitReader.h"
|
||||
#include <media/stagefright/foundation/ABitReader.h>
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace stagefright;
|
||||
|
||||
namespace mp4_demuxer
|
||||
{
|
||||
|
||||
BitReader::BitReader(const mozilla::MediaByteBuffer* aBuffer)
|
||||
: mBitReader(new ABitReader(aBuffer->Elements(), aBuffer->Length()))
|
||||
, mSize(aBuffer->Length()) {}
|
||||
|
||||
BitReader::BitReader(const uint8_t* aBuffer, size_t aLength)
|
||||
: mBitReader(new ABitReader(aBuffer, aLength))
|
||||
, mSize(aLength) {}
|
||||
|
||||
BitReader::~BitReader() {}
|
||||
|
||||
uint32_t
|
||||
BitReader::ReadBits(size_t aNum)
|
||||
{
|
||||
MOZ_ASSERT(aNum <= 32);
|
||||
if (mBitReader->numBitsLeft() < aNum) {
|
||||
return 0;
|
||||
}
|
||||
return mBitReader->getBits(aNum);
|
||||
}
|
||||
|
||||
// Read unsigned integer Exp-Golomb-coded.
|
||||
uint32_t
|
||||
BitReader::ReadUE()
|
||||
{
|
||||
uint32_t i = 0;
|
||||
|
||||
while (ReadBit() == 0 && i < 32) {
|
||||
i++;
|
||||
}
|
||||
if (i == 32) {
|
||||
// This can happen if the data is invalid, or if it's
|
||||
// short, since ReadBit() will return 0 when it runs
|
||||
// off the end of the buffer.
|
||||
NS_WARNING("Invalid H.264 data");
|
||||
return 0;
|
||||
}
|
||||
uint32_t r = ReadBits(i);
|
||||
r += (1 << i) - 1;
|
||||
return r;
|
||||
}
|
||||
|
||||
// Read signed integer Exp-Golomb-coded.
|
||||
int32_t
|
||||
BitReader::ReadSE()
|
||||
{
|
||||
int32_t r = ReadUE();
|
||||
if (r & 1) {
|
||||
return (r+1) / 2;
|
||||
} else {
|
||||
return -r / 2;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t
|
||||
BitReader::ReadU64()
|
||||
{
|
||||
uint64_t hi = ReadU32();
|
||||
uint32_t lo = ReadU32();
|
||||
return (hi << 32) | lo;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
BitReader::ReadUTF8()
|
||||
{
|
||||
int64_t val = ReadBits(8);
|
||||
uint32_t top = (val & 0x80) >> 1;
|
||||
|
||||
if ((val & 0xc0) == 0x80 || val >= 0xFE) {
|
||||
// error.
|
||||
return -1;
|
||||
}
|
||||
while (val & top) {
|
||||
int tmp = ReadBits(8) - 128;
|
||||
if (tmp >> 6) {
|
||||
// error.
|
||||
return -1;
|
||||
}
|
||||
val = (val << 6) + tmp;
|
||||
top <<= 5;
|
||||
}
|
||||
val &= (top << 1) - 1;
|
||||
return val;
|
||||
}
|
||||
|
||||
size_t
|
||||
BitReader::BitCount() const
|
||||
{
|
||||
return mSize * 8 - mBitReader->numBitsLeft();
|
||||
}
|
||||
|
||||
} // namespace mp4_demuxer
|
@ -210,7 +210,8 @@ MP4VideoInfo::Update(const mp4parse_track_info* track,
|
||||
bool
|
||||
MP4VideoInfo::IsValid() const
|
||||
{
|
||||
return mDisplay.width > 0 && mDisplay.height > 0;
|
||||
return (mDisplay.width > 0 && mDisplay.height > 0) ||
|
||||
(mImage.width > 0 && mImage.height > 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/PodOperations.h"
|
||||
#include "mp4_demuxer/AnnexB.h"
|
||||
#include "mp4_demuxer/BitReader.h"
|
||||
#include "mp4_demuxer/ByteReader.h"
|
||||
#include "mp4_demuxer/ByteWriter.h"
|
||||
#include "mp4_demuxer/H264.h"
|
||||
@ -16,63 +17,6 @@ using namespace mozilla;
|
||||
namespace mp4_demuxer
|
||||
{
|
||||
|
||||
class BitReader
|
||||
{
|
||||
public:
|
||||
explicit BitReader(const mozilla::MediaByteBuffer* aBuffer)
|
||||
: mBitReader(aBuffer->Elements(), aBuffer->Length())
|
||||
{
|
||||
}
|
||||
|
||||
uint32_t ReadBits(size_t aNum)
|
||||
{
|
||||
MOZ_ASSERT(aNum <= 32);
|
||||
if (mBitReader.numBitsLeft() < aNum) {
|
||||
return 0;
|
||||
}
|
||||
return mBitReader.getBits(aNum);
|
||||
}
|
||||
|
||||
uint32_t ReadBit()
|
||||
{
|
||||
return ReadBits(1);
|
||||
}
|
||||
|
||||
// Read unsigned integer Exp-Golomb-coded.
|
||||
uint32_t ReadUE()
|
||||
{
|
||||
uint32_t i = 0;
|
||||
|
||||
while (ReadBit() == 0 && i < 32) {
|
||||
i++;
|
||||
}
|
||||
if (i == 32) {
|
||||
// This can happen if the data is invalid, or if it's
|
||||
// short, since ReadBit() will return 0 when it runs
|
||||
// off the end of the buffer.
|
||||
NS_WARNING("Invalid H.264 data");
|
||||
return 0;
|
||||
}
|
||||
uint32_t r = ReadBits(i);
|
||||
r += (1 << i) - 1;
|
||||
return r;
|
||||
}
|
||||
|
||||
// Read signed integer Exp-Golomb-coded.
|
||||
int32_t ReadSE()
|
||||
{
|
||||
int32_t r = ReadUE();
|
||||
if (r & 1) {
|
||||
return (r+1) / 2;
|
||||
} else {
|
||||
return -r / 2;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
stagefright::ABitReader mBitReader;
|
||||
};
|
||||
|
||||
SPSData::SPSData()
|
||||
{
|
||||
PodZero(this);
|
||||
|
45
media/libstagefright/binding/include/mp4_demuxer/BitReader.h
Normal file
45
media/libstagefright/binding/include/mp4_demuxer/BitReader.h
Normal file
@ -0,0 +1,45 @@
|
||||
/* 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 BIT_READER_H_
|
||||
#define BIT_READER_H_
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "MediaData.h"
|
||||
|
||||
namespace stagefright { class ABitReader; }
|
||||
|
||||
namespace mp4_demuxer
|
||||
{
|
||||
|
||||
class BitReader
|
||||
{
|
||||
public:
|
||||
explicit BitReader(const mozilla::MediaByteBuffer* aBuffer);
|
||||
BitReader(const uint8_t* aBuffer, size_t aLength);
|
||||
~BitReader();
|
||||
uint32_t ReadBits(size_t aNum);
|
||||
uint32_t ReadBit() { return ReadBits(1); }
|
||||
uint32_t ReadU32() { return ReadBits(32); }
|
||||
uint64_t ReadU64();
|
||||
|
||||
// Read the UTF-8 sequence and convert it to its 64-bit UCS-4 encoded form.
|
||||
// Return 0xfffffffffffffff if sequence was invalid.
|
||||
uint64_t ReadUTF8();
|
||||
// Read unsigned integer Exp-Golomb-coded.
|
||||
uint32_t ReadUE();
|
||||
// Read signed integer Exp-Golomb-coded.
|
||||
int32_t ReadSE();
|
||||
|
||||
// Return the number of bits parsed so far;
|
||||
size_t BitCount() const;
|
||||
|
||||
private:
|
||||
nsAutoPtr<stagefright::ABitReader> mBitReader;
|
||||
const size_t mSize;
|
||||
};
|
||||
|
||||
} // namespace mp4_demuxer
|
||||
|
||||
#endif // BIT_READER_H_
|
@ -272,7 +272,6 @@ public:
|
||||
const uint8_t* Peek(size_t aCount)
|
||||
{
|
||||
if (aCount > mRemaining) {
|
||||
MOZ_ASSERT(false);
|
||||
return nullptr;
|
||||
}
|
||||
return mPtr;
|
||||
|
@ -52,6 +52,7 @@ EXPORTS.mp4_demuxer += [
|
||||
'binding/include/mp4_demuxer/AnnexB.h',
|
||||
'binding/include/mp4_demuxer/Atom.h',
|
||||
'binding/include/mp4_demuxer/AtomType.h',
|
||||
'binding/include/mp4_demuxer/BitReader.h',
|
||||
'binding/include/mp4_demuxer/BufferStream.h',
|
||||
'binding/include/mp4_demuxer/ByteReader.h',
|
||||
'binding/include/mp4_demuxer/ByteWriter.h',
|
||||
@ -87,6 +88,7 @@ if CONFIG['MOZ_RUST']:
|
||||
UNIFIED_SOURCES += [
|
||||
'binding/Adts.cpp',
|
||||
'binding/AnnexB.cpp',
|
||||
'binding/BitReader.cpp',
|
||||
'binding/Box.cpp',
|
||||
'binding/BufferStream.cpp',
|
||||
'binding/DecoderData.cpp',
|
||||
|
@ -835,6 +835,7 @@ sync_java_files = [TOPSRCDIR + '/mobile/android/services/src/main/java/org/mozil
|
||||
'fxa/FxAccountConstants.java',
|
||||
'fxa/FxAccountDevice.java',
|
||||
'fxa/FxAccountDeviceRegistrator.java',
|
||||
'fxa/FxAccountPushHandler.java',
|
||||
'fxa/login/BaseRequestDelegate.java',
|
||||
'fxa/login/Cohabiting.java',
|
||||
'fxa/login/Doghouse.java',
|
||||
|
@ -21,6 +21,7 @@ import org.mozilla.gecko.GeckoThread;
|
||||
import org.mozilla.gecko.Telemetry;
|
||||
import org.mozilla.gecko.TelemetryContract;
|
||||
import org.mozilla.gecko.annotation.ReflectionTarget;
|
||||
import org.mozilla.gecko.fxa.FxAccountPushHandler;
|
||||
import org.mozilla.gecko.gcm.GcmTokenClient;
|
||||
import org.mozilla.gecko.push.autopush.AutopushClientException;
|
||||
import org.mozilla.gecko.util.BundleEventListener;
|
||||
@ -50,6 +51,7 @@ public class PushService implements BundleEventListener {
|
||||
private static final String LOG_TAG = "GeckoPushService";
|
||||
|
||||
public static final String SERVICE_WEBPUSH = "webpush";
|
||||
public static final String SERVICE_FXA = "fxa";
|
||||
|
||||
private static PushService sInstance;
|
||||
|
||||
@ -63,6 +65,7 @@ public class PushService implements BundleEventListener {
|
||||
"PushServiceAndroidGCM:UnregisterUserAgent",
|
||||
"PushServiceAndroidGCM:SubscribeChannel",
|
||||
"PushServiceAndroidGCM:UnsubscribeChannel",
|
||||
"FxAccountsPush:ReceivedPushMessageToDecode:Response",
|
||||
"History:GetPrePathLastVisitedTimeMilliseconds",
|
||||
};
|
||||
|
||||
@ -150,63 +153,70 @@ public class PushService implements BundleEventListener {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean isWebPush = SERVICE_WEBPUSH.equals(subscription.service);
|
||||
boolean isFxAPush = SERVICE_FXA.equals(subscription.service);
|
||||
if (!isWebPush && !isFxAPush) {
|
||||
Log.e(LOG_TAG, "Message directed to unknown service; dropping: " + subscription.service);
|
||||
return;
|
||||
}
|
||||
|
||||
Log.i(LOG_TAG, "Message directed to service: " + subscription.service);
|
||||
|
||||
if (SERVICE_WEBPUSH.equals(subscription.service)) {
|
||||
if (subscription.serviceData == null) {
|
||||
Log.e(LOG_TAG, "No serviceData found for chid: " + chid + "; ignoring dom/push message.");
|
||||
if (subscription.serviceData == null) {
|
||||
Log.e(LOG_TAG, "No serviceData found for chid: " + chid + "; ignoring dom/push message.");
|
||||
return;
|
||||
}
|
||||
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, TelemetryContract.Method.SERVICE, "dom-push-api");
|
||||
|
||||
final String profileName = subscription.serviceData.optString("profileName", null);
|
||||
final String profilePath = subscription.serviceData.optString("profilePath", null);
|
||||
if (profileName == null || profilePath == null) {
|
||||
Log.e(LOG_TAG, "Corrupt serviceData found for chid: " + chid + "; ignoring dom/push message.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (canSendPushMessagesToGecko) {
|
||||
if (!GeckoThread.canUseProfile(profileName, new File(profilePath))) {
|
||||
Log.e(LOG_TAG, "Mismatched profile for chid: " + chid + "; ignoring dom/push message.");
|
||||
return;
|
||||
}
|
||||
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, TelemetryContract.Method.SERVICE, "dom-push-api");
|
||||
|
||||
final String profileName = subscription.serviceData.optString("profileName", null);
|
||||
final String profilePath = subscription.serviceData.optString("profilePath", null);
|
||||
if (profileName == null || profilePath == null) {
|
||||
Log.e(LOG_TAG, "Corrupt serviceData found for chid: " + chid + "; ignoring dom/push message.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (canSendPushMessagesToGecko) {
|
||||
if (!GeckoThread.canUseProfile(profileName, new File(profilePath))) {
|
||||
Log.e(LOG_TAG, "Mismatched profile for chid: " + chid + "; ignoring dom/push message.");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
final Intent intent = GeckoService.getIntentToCreateServices(context, "android-push-service");
|
||||
GeckoService.setIntentProfile(intent, profileName, profilePath);
|
||||
context.startService(intent);
|
||||
}
|
||||
|
||||
// DELIVERANCE!
|
||||
final JSONObject data = new JSONObject();
|
||||
try {
|
||||
data.put("channelID", chid);
|
||||
data.put("con", bundle.getString("con"));
|
||||
data.put("enc", bundle.getString("enc"));
|
||||
// Only one of cryptokey (newer) and enckey (deprecated) should be set, but the
|
||||
// Gecko handler will verify this.
|
||||
data.put("cryptokey", bundle.getString("cryptokey"));
|
||||
data.put("enckey", bundle.getString("enckey"));
|
||||
data.put("message", bundle.getString("body"));
|
||||
|
||||
if (!canSendPushMessagesToGecko) {
|
||||
data.put("profileName", profileName);
|
||||
data.put("profilePath", profilePath);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
Log.e(LOG_TAG, "Got exception delivering dom/push message to Gecko!", e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (canSendPushMessagesToGecko) {
|
||||
sendMessageToGeckoService(data);
|
||||
} else {
|
||||
Log.i(LOG_TAG, "Service not initialized, adding message to queue.");
|
||||
pendingPushMessages.add(data);
|
||||
}
|
||||
} else {
|
||||
Log.e(LOG_TAG, "Message directed to unknown service; dropping: " + subscription.service);
|
||||
final Intent intent = GeckoService.getIntentToCreateServices(context, "android-push-service");
|
||||
GeckoService.setIntentProfile(intent, profileName, profilePath);
|
||||
context.startService(intent);
|
||||
}
|
||||
|
||||
final JSONObject data = new JSONObject();
|
||||
try {
|
||||
data.put("channelID", chid);
|
||||
data.put("con", bundle.getString("con"));
|
||||
data.put("enc", bundle.getString("enc"));
|
||||
// Only one of cryptokey (newer) and enckey (deprecated) should be set, but the
|
||||
// Gecko handler will verify this.
|
||||
data.put("cryptokey", bundle.getString("cryptokey"));
|
||||
data.put("enckey", bundle.getString("enckey"));
|
||||
data.put("message", bundle.getString("body"));
|
||||
|
||||
if (!canSendPushMessagesToGecko) {
|
||||
data.put("profileName", profileName);
|
||||
data.put("profilePath", profilePath);
|
||||
data.put("service", subscription.service);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
Log.e(LOG_TAG, "Got exception delivering dom/push message to Gecko!", e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (canSendPushMessagesToGecko) {
|
||||
if (isWebPush) {
|
||||
sendMessageToGeckoService(data);
|
||||
} else {
|
||||
sendMessageToDecodeToGeckoService(data);
|
||||
}
|
||||
} else {
|
||||
Log.i(LOG_TAG, "Service not initialized, adding message to queue.");
|
||||
pendingPushMessages.add(data);
|
||||
}
|
||||
}
|
||||
|
||||
@ -217,6 +227,13 @@ public class PushService implements BundleEventListener {
|
||||
GeckoThread.State.PROFILE_READY);
|
||||
}
|
||||
|
||||
protected void sendMessageToDecodeToGeckoService(final @NonNull JSONObject message) {
|
||||
Log.i(LOG_TAG, "Delivering dom/push message to decode to Gecko!");
|
||||
GeckoAppShell.notifyObservers("FxAccountsPush:ReceivedPushMessageToDecode",
|
||||
message.toString(),
|
||||
GeckoThread.State.PROFILE_READY);
|
||||
}
|
||||
|
||||
protected void registerGeckoEventListener() {
|
||||
Log.d(LOG_TAG, "Registered Gecko event listener.");
|
||||
EventDispatcher.getInstance().registerBackgroundThreadListener(this, GECKO_EVENTS);
|
||||
@ -283,6 +300,7 @@ public class PushService implements BundleEventListener {
|
||||
for (JSONObject pushMessage : pendingPushMessages) {
|
||||
final String profileName = pushMessage.optString("profileName", null);
|
||||
final String profilePath = pushMessage.optString("profilePath", null);
|
||||
final String service = pushMessage.optString("service", null);
|
||||
if (profileName == null || profilePath == null ||
|
||||
!GeckoThread.canUseProfile(profileName, new File(profilePath))) {
|
||||
Log.e(LOG_TAG, "Mismatched profile for chid: " +
|
||||
@ -290,7 +308,11 @@ public class PushService implements BundleEventListener {
|
||||
"; ignoring dom/push message.");
|
||||
continue;
|
||||
}
|
||||
sendMessageToGeckoService(pushMessage);
|
||||
if (SERVICE_WEBPUSH.equals(service)) {
|
||||
sendMessageToGeckoService(pushMessage);
|
||||
} else /* FxA Push */ {
|
||||
sendMessageToDecodeToGeckoService(pushMessage);
|
||||
}
|
||||
}
|
||||
pendingPushMessages.clear();
|
||||
callback.sendSuccess(null);
|
||||
@ -320,7 +342,9 @@ public class PushService implements BundleEventListener {
|
||||
return;
|
||||
}
|
||||
if ("PushServiceAndroidGCM:SubscribeChannel".equals(event)) {
|
||||
final String service = SERVICE_WEBPUSH;
|
||||
final String service = SERVICE_FXA.equals(message.getString("service")) ?
|
||||
SERVICE_FXA :
|
||||
SERVICE_WEBPUSH;
|
||||
final JSONObject serviceData;
|
||||
final String appServerKey = message.getString("appServerKey");
|
||||
try {
|
||||
@ -374,6 +398,10 @@ public class PushService implements BundleEventListener {
|
||||
callback.sendError("Could not unsubscribe from channel: " + channelID);
|
||||
return;
|
||||
}
|
||||
if ("FxAccountsPush:ReceivedPushMessageToDecode:Response".equals(event)) {
|
||||
FxAccountPushHandler.handleFxAPushMessage(context, message);
|
||||
return;
|
||||
}
|
||||
if ("History:GetPrePathLastVisitedTimeMilliseconds".equals(event)) {
|
||||
if (callback == null) {
|
||||
Log.e(LOG_TAG, "callback must not be null in " + event);
|
||||
|
170
mobile/android/components/FxAccountsPush.js
Normal file
170
mobile/android/components/FxAccountsPush.js
Normal file
@ -0,0 +1,170 @@
|
||||
/* jshint moz: true, esnext: true */
|
||||
/* 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/. */
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Messaging.jsm");
|
||||
const {
|
||||
PushCrypto,
|
||||
getCryptoParams,
|
||||
} = Cu.import("resource://gre/modules/PushCrypto.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "PushService",
|
||||
"@mozilla.org/push/Service;1", "nsIPushService");
|
||||
XPCOMUtils.defineLazyGetter(this, "_decoder", () => new TextDecoder());
|
||||
|
||||
const FXA_PUSH_SCOPE = "chrome://fxa-push";
|
||||
const Log = Cu.import("resource://gre/modules/AndroidLog.jsm", {}).AndroidLog.bind("FxAccountsPush");
|
||||
|
||||
function FxAccountsPush() {
|
||||
Services.obs.addObserver(this, "FxAccountsPush:ReceivedPushMessageToDecode", false);
|
||||
}
|
||||
|
||||
FxAccountsPush.prototype = {
|
||||
observe: function (subject, topic, data) {
|
||||
switch (topic) {
|
||||
case "android-push-service":
|
||||
if (data === "android-fxa-subscribe") {
|
||||
this._subscribe();
|
||||
} else if (data === "android-fxa-unsubscribe") {
|
||||
this._unsubscribe();
|
||||
}
|
||||
break;
|
||||
case "FxAccountsPush:ReceivedPushMessageToDecode":
|
||||
this._decodePushMessage(data);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_subscribe() {
|
||||
Log.i("FxAccountsPush _subscribe");
|
||||
return new Promise((resolve, reject) => {
|
||||
PushService.subscribe(FXA_PUSH_SCOPE,
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
(result, subscription) => {
|
||||
if (Components.isSuccessCode(result)) {
|
||||
Log.d("FxAccountsPush got subscription");
|
||||
resolve(subscription);
|
||||
} else {
|
||||
Log.w("FxAccountsPush failed to subscribe", result);
|
||||
reject(new Error("FxAccountsPush failed to subscribe"));
|
||||
}
|
||||
});
|
||||
})
|
||||
.then(subscription => {
|
||||
Messaging.sendRequest({
|
||||
type: "FxAccountsPush:Subscribe:Response",
|
||||
subscription: {
|
||||
pushCallback: subscription.endpoint,
|
||||
pushPublicKey: urlsafeBase64Encode(subscription.getKey('p256dh')),
|
||||
pushAuthKey: urlsafeBase64Encode(subscription.getKey('auth'))
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
Log.i("Error when registering FxA push endpoint " + err);
|
||||
});
|
||||
},
|
||||
|
||||
_unsubscribe() {
|
||||
Log.i("FxAccountsPush _unsubscribe");
|
||||
return new Promise((resolve) => {
|
||||
PushService.unsubscribe(FXA_PUSH_SCOPE,
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
(result, ok) => {
|
||||
if (Components.isSuccessCode(result)) {
|
||||
if (ok === true) {
|
||||
Log.d("FxAccountsPush unsubscribed");
|
||||
} else {
|
||||
Log.d("FxAccountsPush had no subscription to unsubscribe");
|
||||
}
|
||||
} else {
|
||||
Log.w("FxAccountsPush failed to unsubscribe", result);
|
||||
}
|
||||
return resolve(ok);
|
||||
});
|
||||
}).catch(err => {
|
||||
Log.e("Error during unsubscribe", err);
|
||||
});
|
||||
},
|
||||
|
||||
_decodePushMessage(data) {
|
||||
Log.i("FxAccountsPush _decodePushMessage");
|
||||
data = JSON.parse(data);
|
||||
let { message, cryptoParams } = this._messageAndCryptoParams(data);
|
||||
return new Promise((resolve, reject) => {
|
||||
PushService.getSubscription(FXA_PUSH_SCOPE,
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
(result, subscription) => {
|
||||
if (!subscription) {
|
||||
return reject(new Error("No subscription found"));
|
||||
}
|
||||
return resolve(subscription);
|
||||
});
|
||||
}).then(subscription => {
|
||||
if (!cryptoParams) {
|
||||
return new Uint8Array();
|
||||
}
|
||||
return PushCrypto.decodeMsg(
|
||||
message,
|
||||
subscription.p256dhPrivateKey,
|
||||
new Uint8Array(subscription.getKey("p256dh")),
|
||||
cryptoParams.dh,
|
||||
cryptoParams.salt,
|
||||
cryptoParams.rs,
|
||||
new Uint8Array(subscription.getKey("auth")),
|
||||
cryptoParams.padSize
|
||||
);
|
||||
})
|
||||
.then(decryptedMessage => {
|
||||
decryptedMessage = _decoder.decode(decryptedMessage);
|
||||
Messaging.sendRequestForResult({
|
||||
type: "FxAccountsPush:ReceivedPushMessageToDecode:Response",
|
||||
message: decryptedMessage
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
Log.d("Error while decoding incoming message : " + err);
|
||||
});
|
||||
},
|
||||
|
||||
// Copied from PushServiceAndroidGCM
|
||||
_messageAndCryptoParams(data) {
|
||||
// Default is no data (and no encryption).
|
||||
let message = null;
|
||||
let cryptoParams = null;
|
||||
|
||||
if (data.message && data.enc && (data.enckey || data.cryptokey)) {
|
||||
let headers = {
|
||||
encryption_key: data.enckey,
|
||||
crypto_key: data.cryptokey,
|
||||
encryption: data.enc,
|
||||
encoding: data.con,
|
||||
};
|
||||
cryptoParams = getCryptoParams(headers);
|
||||
// Ciphertext is (urlsafe) Base 64 encoded.
|
||||
message = ChromeUtils.base64URLDecode(data.message, {
|
||||
// The Push server may append padding.
|
||||
padding: "ignore",
|
||||
});
|
||||
}
|
||||
return { message, cryptoParams };
|
||||
},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
|
||||
|
||||
classID: Components.ID("{d1bbb0fd-1d47-4134-9c12-d7b1be20b721}")
|
||||
};
|
||||
|
||||
function urlsafeBase64Encode(key) {
|
||||
return ChromeUtils.base64URLEncode(new Uint8Array(key), { pad: false });
|
||||
}
|
||||
|
||||
var components = [ FxAccountsPush ];
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
|
@ -96,6 +96,11 @@ contract @mozilla.org/dom/site-specific-user-agent;1 {d5234c9d-0ee2-4b3c-9da3-18
|
||||
component {18a4e042-7c7c-424b-a583-354e68553a7f} FilePicker.js
|
||||
contract @mozilla.org/filepicker;1 {18a4e042-7c7c-424b-a583-354e68553a7f}
|
||||
|
||||
# FxAccountsPush.js
|
||||
component {d1bbb0fd-1d47-4134-9c12-d7b1be20b721} FxAccountsPush.js
|
||||
contract @mozilla.org/fxa-push;1 {d1bbb0fd-1d47-4134-9c12-d7b1be20b721}
|
||||
category android-push-service FxAccountsPush @mozilla.org/fxa-push;1
|
||||
|
||||
#ifndef RELEASE_BUILD
|
||||
# TabSource.js
|
||||
component {5850c76e-b916-4218-b99a-31f004e0a7e7} TabSource.js
|
||||
|
@ -21,6 +21,7 @@ EXTRA_COMPONENTS += [
|
||||
'ContentPermissionPrompt.js',
|
||||
'DirectoryProvider.js',
|
||||
'FilePicker.js',
|
||||
'FxAccountsPush.js',
|
||||
'HelperAppDialog.js',
|
||||
'ImageBlockingPolicy.js',
|
||||
'LoginManagerPrompter.js',
|
||||
|
@ -14,7 +14,7 @@ NO_NDK=1
|
||||
|
||||
. "$topsrcdir/mobile/android/config/mozconfigs/common"
|
||||
|
||||
ac_add_options --with-gradle="$topsrcdir/gradle/bin/gradle"
|
||||
ac_add_options --with-gradle="$topsrcdir/gradle-dist/bin/gradle"
|
||||
export GRADLE_MAVEN_REPOSITORY="file://$topsrcdir/jcentral"
|
||||
|
||||
unset HOST_CC
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user