AAC support
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27581 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
9ed6b85806
commit
6ab381ac31
@ -27,7 +27,7 @@
|
|||||||
#include <MediaFormats.h>
|
#include <MediaFormats.h>
|
||||||
#include "matroska_codecs.h"
|
#include "matroska_codecs.h"
|
||||||
|
|
||||||
//#define TRACE_MATROSKA
|
#define TRACE_MATROSKA
|
||||||
#ifdef TRACE_MATROSKA
|
#ifdef TRACE_MATROSKA
|
||||||
#define TRACE printf
|
#define TRACE printf
|
||||||
#else
|
#else
|
||||||
@ -36,8 +36,6 @@
|
|||||||
|
|
||||||
#define ERROR(a...) fprintf(stderr, a)
|
#define ERROR(a...) fprintf(stderr, a)
|
||||||
|
|
||||||
#define IS_CODEC(a,b) !memcmp(a, b, strlen(b))
|
|
||||||
|
|
||||||
struct bitmap_info_header
|
struct bitmap_info_header
|
||||||
{
|
{
|
||||||
uint32 size;
|
uint32 size;
|
||||||
@ -56,11 +54,13 @@ struct bitmap_info_header
|
|||||||
#include "ogg/ogg.h"
|
#include "ogg/ogg.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
GetAudioFormat(media_format *format, const char *codec, void *private_data, int private_size)
|
GetAudioFormat(media_format *format, const char *codec, void *private_data, int private_size)
|
||||||
{
|
{
|
||||||
TRACE("GetAudioFormat: codec '%s', private data size %d\n", codec, private_size);
|
TRACE("private_data: codec '%s', private data size %d\n", codec, private_size);
|
||||||
|
|
||||||
BMediaFormats formats;
|
BMediaFormats formats;
|
||||||
media_format_description description;
|
media_format_description description;
|
||||||
|
|
||||||
@ -115,7 +115,6 @@ GetAudioFormat(media_format *format, const char *codec, void *private_data, int
|
|||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (IS_CODEC(codec, "A_MPEG/L3")) {
|
if (IS_CODEC(codec, "A_MPEG/L3")) {
|
||||||
media_format_description description;
|
media_format_description description;
|
||||||
@ -127,8 +126,27 @@ GetAudioFormat(media_format *format, const char *codec, void *private_data, int
|
|||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The codec name only has to start with A_AAC to be AAC
|
||||||
if (IS_CODEC(codec, "A_AAC/MPEG4/LC/SBR")) {
|
// The rest is some sort of hint for creating the codec specific data
|
||||||
|
if (IS_CODEC(codec, "A_AAC")) {
|
||||||
|
uint64 misc_codec = 'mp4a';
|
||||||
|
media_format_description description;
|
||||||
|
description.family = B_MISC_FORMAT_FAMILY;
|
||||||
|
description.u.misc.file_format = (uint32)(misc_codec >> 32);
|
||||||
|
description.u.misc.codec = (uint32)misc_codec;
|
||||||
|
if (B_OK != formats.GetFormatFor(description, format))
|
||||||
|
format->type = B_MEDIA_ENCODED_AUDIO;
|
||||||
|
|
||||||
|
// Set the DecoderConfigSize (Not that haiku seems to use it)
|
||||||
|
if (private_size > 0) {
|
||||||
|
TRACE("AAC private data found, size is %d\n", private_size);
|
||||||
|
if (format->SetMetaData(private_data, private_size) != B_OK) {
|
||||||
|
ERROR("Failed to set Decoder Config\n");
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
@ -25,6 +25,8 @@
|
|||||||
#ifndef _MATROSKA_CODECS_H
|
#ifndef _MATROSKA_CODECS_H
|
||||||
#define _MATROSKA_CODECS_H
|
#define _MATROSKA_CODECS_H
|
||||||
|
|
||||||
|
#define IS_CODEC(a,b) !memcmp(a, b, strlen(b))
|
||||||
|
|
||||||
status_t GetAudioFormat(media_format *format, const char *codec, void *private_data, int private_size);
|
status_t GetAudioFormat(media_format *format, const char *codec, void *private_data, int private_size);
|
||||||
status_t GetVideoFormat(media_format *format, const char *codec, void *private_data, int private_size);
|
status_t GetVideoFormat(media_format *format, const char *codec, void *private_data, int private_size);
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
#include "matroska_codecs.h"
|
#include "matroska_codecs.h"
|
||||||
#include "matroska_util.h"
|
#include "matroska_util.h"
|
||||||
|
|
||||||
//#define TRACE_MKV_READER
|
#define TRACE_MKV_READER
|
||||||
#ifdef TRACE_MKV_READER
|
#ifdef TRACE_MKV_READER
|
||||||
#define TRACE printf
|
#define TRACE printf
|
||||||
#else
|
#else
|
||||||
@ -58,6 +58,9 @@ struct mkv_cookie
|
|||||||
unsigned buffer_size;
|
unsigned buffer_size;
|
||||||
|
|
||||||
const TrackInfo *track_info;
|
const TrackInfo *track_info;
|
||||||
|
|
||||||
|
int private_data_size;
|
||||||
|
uint8 * private_data;
|
||||||
|
|
||||||
float frame_rate;
|
float frame_rate;
|
||||||
int64 frame_count;
|
int64 frame_count;
|
||||||
@ -72,12 +75,45 @@ struct mkv_cookie
|
|||||||
uint32 line_count;
|
uint32 line_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static uint8 matroska_samplerate_to_samplerateindex(float samplerate)
|
||||||
|
{
|
||||||
|
if (samplerate <= 7350.0) {
|
||||||
|
return 12;
|
||||||
|
} else if (samplerate <= 8000.0) {
|
||||||
|
return 11;
|
||||||
|
} else if (samplerate <= 11025.0) {
|
||||||
|
return 10;
|
||||||
|
} else if (samplerate <= 12000.0) {
|
||||||
|
return 9;
|
||||||
|
} else if (samplerate <= 16000.0) {
|
||||||
|
return 8;
|
||||||
|
} else if (samplerate <= 22050.0) {
|
||||||
|
return 7;
|
||||||
|
} else if (samplerate <= 24000.0) {
|
||||||
|
return 6;
|
||||||
|
} else if (samplerate <= 32000.0) {
|
||||||
|
return 5;
|
||||||
|
} else if (samplerate <= 44100.0) {
|
||||||
|
return 4;
|
||||||
|
} else if (samplerate <= 48000.0) {
|
||||||
|
return 3;
|
||||||
|
} else if (samplerate <= 64000.0) {
|
||||||
|
return 2;
|
||||||
|
} else if (samplerate <= 88200.0) {
|
||||||
|
return 1;
|
||||||
|
} else if (samplerate <= 96000.0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 15;
|
||||||
|
}
|
||||||
|
|
||||||
mkvReader::mkvReader()
|
mkvReader::mkvReader()
|
||||||
: fInputStream(0)
|
: fInputStream(0)
|
||||||
, fFile(0)
|
, fFile(0)
|
||||||
, fFileInfo(0)
|
, fFileInfo(0)
|
||||||
{
|
{
|
||||||
|
fakeExtraData = 0;
|
||||||
TRACE("mkvReader::mkvReader\n");
|
TRACE("mkvReader::mkvReader\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,15 +122,71 @@ mkvReader::~mkvReader()
|
|||||||
{
|
{
|
||||||
mkv_Close(fFile);
|
mkv_Close(fFile);
|
||||||
free(fInputStream);
|
free(fInputStream);
|
||||||
|
if (fakeExtraData) {
|
||||||
|
delete [] fakeExtraData;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
mkvReader::CreateFakeAACDecoderConfig(const TrackInfo *track)
|
||||||
|
{
|
||||||
|
// Try to fake up a valid Decoder Config for the AAC decoder to parse
|
||||||
|
TRACE("AAC requires private data (attempting to fake one).\n");
|
||||||
|
|
||||||
|
fakeExtraData = new uint8[8];
|
||||||
|
|
||||||
|
int Profile = 1;
|
||||||
|
|
||||||
|
if (strstr(track->CodecID,"MAIN")) {
|
||||||
|
Profile = 1;
|
||||||
|
} else if (strstr(track->CodecID,"LC")) {
|
||||||
|
Profile = 2;
|
||||||
|
} else if (strstr(track->CodecID,"SSR")) {
|
||||||
|
Profile = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 SampleRateIndex = matroska_samplerate_to_samplerateindex(track->Audio.SamplingFreq);
|
||||||
|
|
||||||
|
// profile 5 bits
|
||||||
|
// SampleRateIndex 4 bits
|
||||||
|
// Channels 4 Bits
|
||||||
|
fakeExtraData[0] = (Profile << 3) | ((SampleRateIndex & 0x0E) >> 1);
|
||||||
|
fakeExtraData[1] = ((SampleRateIndex & 0x01) << 7) | (track->Audio.Channels << 3);
|
||||||
|
if (strstr(track->CodecID, "SBR")) {
|
||||||
|
// Sync Extension 0x2b7 11 bits
|
||||||
|
// Extension Audio Object Type 0x5 5 bits
|
||||||
|
// SBR present flag 0x1 1 bit
|
||||||
|
// SampleRateIndex 3 bits
|
||||||
|
// if SampleRateIndex = 15
|
||||||
|
// ExtendedSamplingFrequency 24 bits
|
||||||
|
|
||||||
|
SampleRateIndex = matroska_samplerate_to_samplerateindex(track->Audio.OutputSamplingFreq);
|
||||||
|
fakeExtraData[2] = 0x56;
|
||||||
|
fakeExtraData[3] = 0xE5;
|
||||||
|
if (SampleRateIndex != 15) {
|
||||||
|
fakeExtraData[4] = 0x80 | (SampleRateIndex << 3);
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 SampleRate = uint32(track->Audio.OutputSamplingFreq);
|
||||||
|
|
||||||
|
fakeExtraData[4] = 0x80 | (SampleRateIndex << 3) | ((SampleRate & 0xFFF0 ) >> 4);
|
||||||
|
fakeExtraData[5] = (SampleRate & 0x0FFF) << 4;
|
||||||
|
fakeExtraData[6] = SampleRate << 12;
|
||||||
|
fakeExtraData[7] = SampleRate << 20;
|
||||||
|
return 8;
|
||||||
|
} else {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
mkvReader::Copyright()
|
mkvReader::Copyright()
|
||||||
{
|
{
|
||||||
return "Matroska reader, " B_UTF8_COPYRIGHT " by Marcus Overhagen";
|
return "Matroska reader, " B_UTF8_COPYRIGHT " by Marcus Overhagen";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
mkvReader::Sniff(int32 *streamCount)
|
mkvReader::Sniff(int32 *streamCount)
|
||||||
@ -236,6 +328,9 @@ mkvReader::SetupVideoCookie(mkv_cookie *cookie)
|
|||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cookie->private_data = (uint8 *)cookie->track_info->CodecPrivate;
|
||||||
|
cookie->private_data_size = cookie->track_info->CodecPrivateSize;
|
||||||
|
|
||||||
uint16 width_aspect_ratio;
|
uint16 width_aspect_ratio;
|
||||||
uint16 height_aspect_ratio;
|
uint16 height_aspect_ratio;
|
||||||
get_pixel_aspect_ratio(&width_aspect_ratio, &height_aspect_ratio,
|
get_pixel_aspect_ratio(&width_aspect_ratio, &height_aspect_ratio,
|
||||||
@ -287,22 +382,33 @@ mkvReader::SetupAudioCookie(mkv_cookie *cookie)
|
|||||||
|
|
||||||
cookie->frame_rate = cookie->track_info->Audio.SamplingFreq;
|
cookie->frame_rate = cookie->track_info->Audio.SamplingFreq;
|
||||||
cookie->duration = get_duration_in_us(fFileInfo->Duration);
|
cookie->duration = get_duration_in_us(fFileInfo->Duration);
|
||||||
cookie->frame_count = get_frame_count_by_frame_rate(fFileInfo->Duration, cookie->track_info->Audio.SamplingFreq);
|
cookie->frame_count = get_frame_count_by_frame_rate(fFileInfo->Duration, cookie->frame_rate);
|
||||||
|
|
||||||
TRACE("frame_rate: %.6f\n", cookie->frame_rate);
|
TRACE("frame_rate: %.6f\n", cookie->frame_rate);
|
||||||
TRACE("duration: %Ld (%.6f)\n", cookie->duration, cookie->duration / 1E6);
|
TRACE("duration: %Ld (%.6f)\n", cookie->duration, cookie->duration / 1E6);
|
||||||
TRACE("frame_count: %Ld\n", cookie->frame_count);
|
TRACE("frame_count: %Ld\n", cookie->frame_count);
|
||||||
|
|
||||||
status_t res;
|
if (B_OK != GetAudioFormat(&cookie->format, cookie->track_info->CodecID, cookie->track_info->CodecPrivate, cookie->track_info->CodecPrivateSize)) {
|
||||||
res = GetAudioFormat(&cookie->format, cookie->track_info->CodecID, cookie->track_info->CodecPrivate, cookie->track_info->CodecPrivateSize);
|
|
||||||
if (res != B_OK) {
|
|
||||||
TRACE("mkvReader::SetupAudioCookie: codec not recognized\n");
|
TRACE("mkvReader::SetupAudioCookie: codec not recognized\n");
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
cookie->format.u.encoded_audio.bit_rate = cookie->track_info->Audio.BitDepth * cookie->track_info->Audio.Channels * cookie->track_info->Audio.SamplingFreq;
|
cookie->format.u.encoded_audio.output.frame_rate = cookie->frame_rate;
|
||||||
cookie->format.u.encoded_audio.output.frame_rate = cookie->track_info->Audio.SamplingFreq;
|
|
||||||
cookie->format.u.encoded_audio.output.channel_count = cookie->track_info->Audio.Channels;
|
cookie->format.u.encoded_audio.output.channel_count = cookie->track_info->Audio.Channels;
|
||||||
|
cookie->format.u.encoded_audio.bit_rate = cookie->track_info->Audio.BitDepth * cookie->format.u.encoded_audio.output.channel_count * cookie->frame_rate;
|
||||||
|
|
||||||
|
cookie->private_data = (uint8 *)cookie->track_info->CodecPrivate;
|
||||||
|
cookie->private_data_size = cookie->track_info->CodecPrivateSize;
|
||||||
|
|
||||||
|
if (IS_CODEC(cookie->track_info->CodecID, "A_AAC")) {
|
||||||
|
if (cookie->private_data_size == 0) {
|
||||||
|
cookie->private_data_size = CreateFakeAACDecoderConfig(cookie->track_info);
|
||||||
|
cookie->private_data = &fakeExtraData[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
cookie->format.u.encoded_audio.output.format = media_raw_audio_format::B_AUDIO_SHORT;
|
||||||
|
cookie->format.u.encoded_audio.bit_rate = 64000 * cookie->format.u.encoded_audio.output.channel_count;
|
||||||
|
}
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@ -339,8 +445,8 @@ mkvReader::GetStreamInfo(void *_cookie, int64 *frameCount, bigtime_t *duration,
|
|||||||
*frameCount = cookie->frame_count;
|
*frameCount = cookie->frame_count;
|
||||||
*duration = cookie->duration;
|
*duration = cookie->duration;
|
||||||
*format = cookie->format;
|
*format = cookie->format;
|
||||||
*infoBuffer = 0;
|
*infoBuffer = cookie->private_data;
|
||||||
*infoSize = 0;
|
*infoSize = cookie->private_data_size;
|
||||||
}
|
}
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
@ -62,11 +62,13 @@ private:
|
|||||||
status_t SetupVideoCookie(mkv_cookie *cookie);
|
status_t SetupVideoCookie(mkv_cookie *cookie);
|
||||||
status_t SetupAudioCookie(mkv_cookie *cookie);
|
status_t SetupAudioCookie(mkv_cookie *cookie);
|
||||||
status_t SetupTextCookie(mkv_cookie *cookie);
|
status_t SetupTextCookie(mkv_cookie *cookie);
|
||||||
|
int CreateFakeAACDecoderConfig(const TrackInfo *track);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
InputStream * fInputStream;
|
InputStream * fInputStream;
|
||||||
MatroskaFile * fFile;
|
MatroskaFile * fFile;
|
||||||
const SegmentInfo * fFileInfo;
|
const SegmentInfo * fFileInfo;
|
||||||
|
uint8 * fakeExtraData;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user