Bug 1195723: [flac] P12. Add sniffer for streaming flac. r=kamidphish

MozReview-Commit-ID: P62v6vsXzs

--HG--
extra : rebase_source : 37c365efbff607b10ad41ce8290556ded07783e2
This commit is contained in:
Jean-Yves Avenard 2016-08-18 13:07:11 +10:00
Родитель 6d13063ab5
Коммит a637a5b7d5
3 изменённых файлов: 66 добавлений и 27 удалений

Просмотреть файл

@ -236,12 +236,42 @@ const uint8_t FrameHeader::CRC8Table[256] =
class Frame {
public:
// Find the next frame start in the current resource.
// On exit return true, offset is set and resource points to the frame found.
// The FLAC signature is made of 14 bits set to 1; however the 15th bit is
// mandatorily set to 0, so we need to find either of 0xfffc or 0xfffd 2-bytes
// signature. We first use a bitmask to see if 0xfc or 0xfd is present. And if
// so we check for the whole signature.
// aData must be pointing to a buffer at least
// aLength + FLAC_MAX_FRAME_HEADER_SIZE bytes.
int64_t FindNext(const uint8_t* aData, const uint32_t aLength)
{
uint32_t modOffset = aLength % 4;
uint32_t i, j;
for (i = 0; i < modOffset; i++) {
if ((BigEndian::readUint16(aData + i) & 0xfffe) == 0xfff8) {
if (mHeader.Parse(aData + i)) {
return i;
}
}
}
for (; i < aLength; i += 4) {
uint32_t x = BigEndian::readUint32(aData + i);
if (((x & ~(x + 0x01010101)) & 0x80808080)) {
for (j = 0; j < 4; j++) {
if ((BigEndian::readUint16(aData + i + j) & 0xfffe) == 0xfff8) {
if (mHeader.Parse(aData + i + j)) {
return i + j;
}
}
}
}
}
return -1;
}
// Find the next frame start in the current resource.
// On exit return true, offset is set and resource points to the frame found.
bool FindNext(MediaResourceIndex& aResource)
{
static const int BUFFER_SIZE = 4096;
@ -261,6 +291,7 @@ public:
if (NS_FAILED(rv)) {
return false;
}
if (read < FLAC_MAX_FRAME_HEADER_SIZE) {
// Assume that we can't have a valid frame in such small content, we
// must have reached EOS.
@ -270,32 +301,12 @@ public:
}
const size_t bufSize = read + innerOffset - FLAC_MAX_FRAME_HEADER_SIZE;
int64_t foundOffset =
FindNext(reinterpret_cast<uint8_t*>(buffer.Elements()), bufSize);
const uint8_t* buf = reinterpret_cast<uint8_t*>(buffer.Elements());
uint32_t modOffset = bufSize % 4;
uint32_t i, j;
for (i = 0; i < modOffset; i++) {
if ((BigEndian::readUint16(buf + i) & 0xfffe) == 0xfff8) {
if (mHeader.Parse(buf + i)) {
SetOffset(aResource, offset + i);
return true;
}
}
}
for (; i < bufSize; i += 4) {
uint32_t x = BigEndian::readUint32(buf + i);
if (((x & ~(x + 0x01010101)) & 0x80808080)) {
for (j = 0; j < 4; j++) {
if ((BigEndian::readUint16(buf + i + j) & 0xfffe) == 0xfff8) {
if (mHeader.Parse(buf + i + j)) {
SetOffset(aResource, offset + i + j);
return true;
}
}
}
}
if (foundOffset >= 0) {
SetOffset(aResource, foundOffset + offset);
return true;
}
// Scan the next block;
@ -1039,4 +1050,15 @@ FlacTrackDemuxer::TimeAtEnd()
return mParsedFramesDuration;
}
/* static */ bool
FlacDemuxer::FlacSniffer(const uint8_t* aData, const uint32_t aLength)
{
if (aLength < FLAC_MAX_FRAME_HEADER_SIZE) {
return false;
}
flac::Frame frame;
return frame.FindNext(aData, aLength - FLAC_MAX_FRAME_HEADER_SIZE) >= 0;
}
} // namespace mozilla

Просмотреть файл

@ -30,6 +30,9 @@ public:
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();

Просмотреть файл

@ -12,6 +12,7 @@
#include "mozilla/ModuleUtils.h"
#include "mp3sniff.h"
#include "nestegg/nestegg.h"
#include "FlacDemuxer.h"
#include "nsIClassInfoImpl.h"
#include <algorithm>
@ -120,6 +121,11 @@ static bool MatchesMP3(const uint8_t* aData, const uint32_t aLength)
return mp3_sniff(aData, (long)aLength);
}
static bool MatchesFLAC(const uint8_t* aData, const uint32_t aLength)
{
return mozilla::FlacDemuxer::FlacSniffer(aData, aLength);
}
NS_IMETHODIMP
nsMediaSniffer::GetMIMETypeFromContent(nsIRequest* aRequest,
const uint8_t* aData,
@ -179,6 +185,14 @@ nsMediaSniffer::GetMIMETypeFromContent(nsIRequest* aRequest,
return NS_OK;
}
// Flac frames are generally big, often in excess of 24kB.
// Using a size of MAX_BYTES_SNIFFED effectively means that we will only
// recognize flac content if it starts with a frame.
if (MatchesFLAC(aData, clampedLength)) {
aSniffedType.AssignLiteral(AUDIO_FLAC);
return NS_OK;
}
// Could not sniff the media type, we are required to set it to
// application/octet-stream.
aSniffedType.AssignLiteral(APPLICATION_OCTET_STREAM);