Merge autoland to m-c. a=merge

This commit is contained in:
Ryan VanderMeulen 2016-08-22 09:37:44 -04:00
commit 14b640ba33
137 changed files with 7217 additions and 606 deletions

View File

@ -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({});

View File

@ -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

View File

@ -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);

View File

@ -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) {

View File

@ -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;

View 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>

View File

@ -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

View File

@ -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]

View 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>

View 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>

View File

@ -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 =

View File

@ -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;

View File

@ -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;

View File

@ -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();

View File

@ -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"));
}

View File

@ -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,

View File

@ -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);

View File

@ -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
IsOggType(const nsACString& aType)
IsOggSupportedType(const nsACString& aType,
const nsAString& aCodecs = EmptyString())
{
if (!MediaDecoder::IsOggEnabled()) {
return false;
return OggDecoder::CanHandleMediaType(aType, aCodecs);
}
return CodecListContains(gOggTypes, aType);
static bool
IsOggTypeAndEnabled(const nsACString& 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

View File

@ -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);
}

View File

@ -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;

View File

@ -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();

View 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

View 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_

File diff suppressed because it is too large Load Diff

View 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_

View 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

View 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
View 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']

View File

@ -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;

View File

@ -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) {

View File

@ -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

View File

@ -21,6 +21,7 @@ with Files('GetUserMedia*'):
DIRS += [
'encoder',
'flac',
'gmp',
'gmp-plugin',
'gmp-plugin-openh264',

View File

@ -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)]

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
{

View File

@ -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);
}
}

View File

@ -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;

View File

@ -21,9 +21,11 @@ FFmpegAudioDecoder<LIBAV_VER>::FFmpegAudioDecoder(FFmpegLibWrapper* aLib,
{
MOZ_COUNT_CTOR(FFmpegAudioDecoder);
// Use a new MediaByteBuffer as the object will be modified during initialization.
if (aConfig.mCodecSpecificConfig && aConfig.mCodecSpecificConfig->Length()) {
mExtraData = new MediaByteBuffer;
mExtraData->AppendElements(*aConfig.mCodecSpecificConfig);
}
}
RefPtr<MediaDataDecoder::InitPromise>
FFmpegAudioDecoder<LIBAV_VER>::Init()
@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -10,6 +10,7 @@ EXPORTS += [
]
UNIFIED_SOURCES += [
'../FFmpegAudioDecoder.cpp',
'../FFmpegDataDecoder.cpp',
'../FFmpegDecoderModule.cpp',
'../FFmpegVideoDecoder.cpp',

BIN
dom/media/test/A4.ogv Normal file

Binary file not shown.

View File

@ -0,0 +1 @@
Cache-Control: no-store

Binary file not shown.

View File

@ -0,0 +1 @@
Cache-Control: no-store

Binary file not shown.

View File

@ -0,0 +1 @@
Cache-Control: no-store

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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,

View File

@ -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,7 +891,23 @@ this.PushService = {
cryptoParams.rs,
record.authenticationSecret,
cryptoParams.padSize
).then(message => this._notifyApp(record, messageID, message), 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,

View File

@ -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,17 +76,24 @@ this.PushServiceAndroidGCM = {
},
observe: function(subject, topic, data) {
if (topic == "nsPref:changed") {
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);
}
return;
break;
case "PushServiceAndroidGCM:ReceivedPushMessage":
this._onPushMessageReceived(data);
break;
default:
break;
}
},
if (topic == "PushServiceAndroidGCM:ReceivedPushMessage") {
_onPushMessageReceived(data) {
// TODO: Use Messaging.jsm for this.
if (this._mainPushService == null) {
// Shouldn't ever happen, but let's be careful.
@ -100,6 +107,17 @@ this.PushServiceAndroidGCM = {
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;
@ -118,15 +136,7 @@ this.PushServiceAndroidGCM = {
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;
});
return;
}
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],

View File

@ -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."));

View File

@ -142,7 +142,7 @@ AccessibleCaret::SetSelectionBarEnabled(bool aEnabled)
mSelectionBarEnabled = aEnabled;
}
/* static */ nsString
/* static */ nsAutoString
AccessibleCaret::AppearanceString(Appearance aAppearance)
{
nsAutoString string;

View File

@ -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;

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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,

View 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 */
}

View 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 */

View 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,
};

View 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
};

View 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 */

View 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,
};

View 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);
}

View 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 */

View 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.
*/

View 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;
}
}

View 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,};

View 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 */

View File

@ -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',

View 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 */

View 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

View 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 */
}

View File

@ -6,6 +6,8 @@
SOURCES += [
'constants.c',
'flacdsp.asm',
'flacdsp_init.c',
'h264_intrapred.asm',
'h264_intrapred_10bit.asm',
'h264_intrapred_init.c',

View 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

View File

@ -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);
}
}

View File

@ -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);

View 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_

View File

@ -272,7 +272,6 @@ public:
const uint8_t* Peek(size_t aCount)
{
if (aCount > mRemaining) {
MOZ_ASSERT(false);
return nullptr;
}
return mPtr;

View File

@ -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',

View File

@ -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',

View File

@ -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,9 +153,15 @@ 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.");
return;
@ -178,7 +187,6 @@ public class PushService implements BundleEventListener {
context.startService(intent);
}
// DELIVERANCE!
final JSONObject data = new JSONObject();
try {
data.put("channelID", chid);
@ -193,6 +201,7 @@ public class PushService implements BundleEventListener {
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);
@ -200,14 +209,15 @@ public class PushService implements BundleEventListener {
}
if (canSendPushMessagesToGecko) {
if (isWebPush) {
sendMessageToGeckoService(data);
} else {
sendMessageToDecodeToGeckoService(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);
}
}
protected void sendMessageToGeckoService(final @NonNull JSONObject message) {
@ -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;
}
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);

View 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);

View File

@ -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

View File

@ -21,6 +21,7 @@ EXTRA_COMPONENTS += [
'ContentPermissionPrompt.js',
'DirectoryProvider.js',
'FilePicker.js',
'FxAccountsPush.js',
'HelperAppDialog.js',
'ImageBlockingPolicy.js',
'LoginManagerPrompter.js',

View File

@ -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