commit
7fa505e059
@ -0,0 +1,624 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
//#define LOG_NDEBUG 0
|
||||
#define LOG_TAG "AC4Parser"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/misc.h>
|
||||
|
||||
#include "AC4Parser.h"
|
||||
|
||||
#define BOOLSTR(a) ((a)?"true":"false")
|
||||
#define BYTE_ALIGN mBitReader.skipBits(mBitReader.numBitsLeft() % 8)
|
||||
#define CHECK_BITS_LEFT(n) if (mBitReader.numBitsLeft() < n) {return false;}
|
||||
|
||||
namespace android {
|
||||
|
||||
AC4Parser::AC4Parser() {
|
||||
}
|
||||
|
||||
AC4DSIParser::AC4DSIParser(ABitReader &br)
|
||||
: mBitReader(br){
|
||||
|
||||
mDSISize = mBitReader.numBitsLeft();
|
||||
}
|
||||
|
||||
// ETSI TS 103 190-2 V1.1.1 (2015-09) Table 79: channel_mode
|
||||
static const char *ChannelModes[] = {
|
||||
"mono",
|
||||
"stereo",
|
||||
"3.0",
|
||||
"5.0",
|
||||
"5.1",
|
||||
"7.0 (3/4/0)",
|
||||
"7.1 (3/4/0.1)",
|
||||
"7.0 (5/2/0)",
|
||||
"7.1 (5/2/0.1)",
|
||||
"7.0 (3/2/2)",
|
||||
"7.1 (3/2/2.1)",
|
||||
"7.0.4",
|
||||
"7.1.4",
|
||||
"9.0.4",
|
||||
"9.1.4",
|
||||
"22.2"
|
||||
};
|
||||
|
||||
static const char* ContentClassifier[] = {
|
||||
"Complete Main",
|
||||
"Music and Effects",
|
||||
"Visually Impaired",
|
||||
"Hearing Impaired",
|
||||
"Dialog",
|
||||
"Commentary",
|
||||
"Emergency",
|
||||
"Voice Over"
|
||||
};
|
||||
|
||||
bool AC4DSIParser::parseLanguageTag(uint32_t presentationID, uint32_t substreamID){
|
||||
CHECK_BITS_LEFT(6);
|
||||
uint32_t n_language_tag_bytes = mBitReader.getBits(6);
|
||||
if (n_language_tag_bytes < 2 || n_language_tag_bytes >= 42) {
|
||||
return false;
|
||||
}
|
||||
CHECK_BITS_LEFT(n_language_tag_bytes * 8);
|
||||
char language_tag_bytes[42]; // TS 103 190 part 1 4.3.3.8.7
|
||||
for (uint32_t i = 0; i < n_language_tag_bytes; i++) {
|
||||
language_tag_bytes[i] = (char)mBitReader.getBits(8);
|
||||
}
|
||||
language_tag_bytes[n_language_tag_bytes] = 0;
|
||||
ALOGV("%u.%u: language_tag = %s\n", presentationID, substreamID, language_tag_bytes);
|
||||
|
||||
std::string language(language_tag_bytes, n_language_tag_bytes);
|
||||
mPresentations[presentationID].mLanguage = language;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// TS 103 190-1 v1.2.1 E.5 and TS 103 190-2 v1.1.1 E.9
|
||||
bool AC4DSIParser::parseSubstreamDSI(uint32_t presentationID, uint32_t substreamID){
|
||||
CHECK_BITS_LEFT(5);
|
||||
uint32_t channel_mode = mBitReader.getBits(5);
|
||||
CHECK_BITS_LEFT(2);
|
||||
uint32_t dsi_sf_multiplier = mBitReader.getBits(2);
|
||||
CHECK_BITS_LEFT(1);
|
||||
bool b_substream_bitrate_indicator = (mBitReader.getBits(1) == 1);
|
||||
ALOGV("%u.%u: channel_mode = %u (%s)\n", presentationID, substreamID, channel_mode,
|
||||
channel_mode < NELEM(ChannelModes) ? ChannelModes[channel_mode] : "reserved");
|
||||
ALOGV("%u.%u: dsi_sf_multiplier = %u\n", presentationID,
|
||||
substreamID, dsi_sf_multiplier);
|
||||
ALOGV("%u.%u: b_substream_bitrate_indicator = %s\n", presentationID,
|
||||
substreamID, BOOLSTR(b_substream_bitrate_indicator));
|
||||
|
||||
if (b_substream_bitrate_indicator) {
|
||||
CHECK_BITS_LEFT(5);
|
||||
uint32_t substream_bitrate_indicator = mBitReader.getBits(5);
|
||||
ALOGV("%u.%u: substream_bitrate_indicator = %u\n", presentationID, substreamID,
|
||||
substream_bitrate_indicator);
|
||||
}
|
||||
if (channel_mode >= 7 && channel_mode <= 10) {
|
||||
CHECK_BITS_LEFT(1);
|
||||
uint32_t add_ch_base = mBitReader.getBits(1);
|
||||
ALOGV("%u.%u: add_ch_base = %u\n", presentationID, substreamID, add_ch_base);
|
||||
}
|
||||
CHECK_BITS_LEFT(1);
|
||||
bool b_content_type = (mBitReader.getBits(1) == 1);
|
||||
ALOGV("%u.%u: b_content_type = %s\n", presentationID, substreamID, BOOLSTR(b_content_type));
|
||||
if (b_content_type) {
|
||||
CHECK_BITS_LEFT(3);
|
||||
uint32_t content_classifier = mBitReader.getBits(3);
|
||||
ALOGV("%u.%u: content_classifier = %u (%s)\n", presentationID, substreamID,
|
||||
content_classifier, ContentClassifier[content_classifier]);
|
||||
|
||||
// For streams based on TS 103 190 part 1 the presentation level channel_mode doesn't
|
||||
// exist and so we use the channel_mode from either the CM or M&E substream
|
||||
// (they are mutually exclusive)
|
||||
if (mPresentations[presentationID].mChannelMode == -1 &&
|
||||
(content_classifier == 0 || content_classifier == 1)) {
|
||||
mPresentations[presentationID].mChannelMode = channel_mode;
|
||||
}
|
||||
mPresentations[presentationID].mContentClassifier = content_classifier;
|
||||
CHECK_BITS_LEFT(1);
|
||||
bool b_language_indicator = (mBitReader.getBits(1) == 1);
|
||||
ALOGV("%u.%u: b_language_indicator = %s\n", presentationID, substreamID,
|
||||
BOOLSTR(b_language_indicator));
|
||||
if (b_language_indicator) {
|
||||
if (!parseLanguageTag(presentationID, substreamID)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ETSI TS 103 190-2 v1.1.1 section E.11
|
||||
bool AC4DSIParser::parseSubstreamGroupDSI(uint32_t presentationID, uint32_t groupID)
|
||||
{
|
||||
CHECK_BITS_LEFT(1);
|
||||
bool b_substreams_present = (mBitReader.getBits(1) == 1);
|
||||
CHECK_BITS_LEFT(1);
|
||||
bool b_hsf_ext = (mBitReader.getBits(1) == 1);
|
||||
CHECK_BITS_LEFT(1);
|
||||
bool b_channel_coded = (mBitReader.getBits(1) == 1);
|
||||
CHECK_BITS_LEFT(8);
|
||||
uint32_t n_substreams = mBitReader.getBits(8);
|
||||
ALOGV("%u.%u: b_substreams_present = %s\n", presentationID, groupID,
|
||||
BOOLSTR(b_substreams_present));
|
||||
ALOGV("%u.%u: b_hsf_ext = %s\n", presentationID, groupID, BOOLSTR(b_hsf_ext));
|
||||
ALOGV("%u.%u: b_channel_coded = %s\n", presentationID, groupID, BOOLSTR(b_channel_coded));
|
||||
ALOGV("%u.%u: n_substreams = %u\n", presentationID, groupID, n_substreams);
|
||||
|
||||
for (uint32_t i = 0; i < n_substreams; i++) {
|
||||
CHECK_BITS_LEFT(2);
|
||||
uint32_t dsi_sf_multiplier = mBitReader.getBits(2);
|
||||
CHECK_BITS_LEFT(1);
|
||||
bool b_substream_bitrate_indicator = (mBitReader.getBits(1) == 1);
|
||||
ALOGV("%u.%u.%u: dsi_sf_multiplier = %u\n", presentationID, groupID, i, dsi_sf_multiplier);
|
||||
ALOGV("%u.%u.%u: b_substream_bitrate_indicator = %s\n", presentationID, groupID, i,
|
||||
BOOLSTR(b_substream_bitrate_indicator));
|
||||
|
||||
if (b_substream_bitrate_indicator) {
|
||||
CHECK_BITS_LEFT(5);
|
||||
uint32_t substream_bitrate_indicator = mBitReader.getBits(5);
|
||||
ALOGV("%u.%u.%u: substream_bitrate_indicator = %u\n", presentationID, groupID, i,
|
||||
substream_bitrate_indicator);
|
||||
}
|
||||
if (b_channel_coded) {
|
||||
CHECK_BITS_LEFT(24);
|
||||
uint32_t dsi_substream_channel_mask = mBitReader.getBits(24);
|
||||
ALOGV("%u.%u.%u: dsi_substream_channel_mask = 0x%06x\n", presentationID, groupID, i,
|
||||
dsi_substream_channel_mask);
|
||||
} else {
|
||||
CHECK_BITS_LEFT(1);
|
||||
bool b_ajoc = (mBitReader.getBits(1) == 1);
|
||||
ALOGV("%u.%u.%u: b_ajoc = %s\n", presentationID, groupID, i, BOOLSTR(b_ajoc));
|
||||
if (b_ajoc) {
|
||||
CHECK_BITS_LEFT(1);
|
||||
bool b_static_dmx = (mBitReader.getBits(1) == 1);
|
||||
ALOGV("%u.%u.%u: b_static_dmx = %s\n", presentationID, groupID, i,
|
||||
BOOLSTR(b_static_dmx));
|
||||
if (!b_static_dmx) {
|
||||
CHECK_BITS_LEFT(4);
|
||||
uint32_t n_dmx_objects_minus1 = mBitReader.getBits(4);
|
||||
ALOGV("%u.%u.%u: n_dmx_objects_minus1 = %u\n", presentationID, groupID, i,
|
||||
n_dmx_objects_minus1);
|
||||
}
|
||||
CHECK_BITS_LEFT(6);
|
||||
uint32_t n_umx_objects_minus1 = mBitReader.getBits(6);
|
||||
ALOGV("%u.%u.%u: n_umx_objects_minus1 = %u\n", presentationID, groupID, i,
|
||||
n_umx_objects_minus1);
|
||||
}
|
||||
CHECK_BITS_LEFT(4);
|
||||
mBitReader.skipBits(4); // objects_assignment_mask
|
||||
}
|
||||
}
|
||||
|
||||
CHECK_BITS_LEFT(1);
|
||||
bool b_content_type = (mBitReader.getBits(1) == 1);
|
||||
ALOGV("%u.%u: b_content_type = %s\n", presentationID, groupID, BOOLSTR(b_content_type));
|
||||
if (b_content_type) {
|
||||
CHECK_BITS_LEFT(3);
|
||||
uint32_t content_classifier = mBitReader.getBits(3);
|
||||
ALOGV("%u.%u: content_classifier = %s (%u)\n", presentationID, groupID,
|
||||
ContentClassifier[content_classifier], content_classifier);
|
||||
|
||||
mPresentations[presentationID].mContentClassifier = content_classifier;
|
||||
|
||||
CHECK_BITS_LEFT(1);
|
||||
bool b_language_indicator = (mBitReader.getBits(1) == 1);
|
||||
ALOGV("%u.%u: b_language_indicator = %s\n", presentationID, groupID,
|
||||
BOOLSTR(b_language_indicator));
|
||||
|
||||
if (b_language_indicator) {
|
||||
if (!parseLanguageTag(presentationID, groupID)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AC4DSIParser::parseBitrateDsi() {
|
||||
CHECK_BITS_LEFT(2 + 32 + 32);
|
||||
mBitReader.skipBits(2); // bit_rate_mode
|
||||
mBitReader.skipBits(32); // bit_rate
|
||||
mBitReader.skipBits(32); // bit_rate_precision
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// TS 103 190-1 section E.4 (ac4_dsi) and TS 103 190-2 section E.6 (ac4_dsi_v1)
|
||||
bool AC4DSIParser::parse() {
|
||||
CHECK_BITS_LEFT(3);
|
||||
uint32_t ac4_dsi_version = mBitReader.getBits(3);
|
||||
if (ac4_dsi_version > 1) {
|
||||
ALOGE("error while parsing ac-4 dsi: only versions 0 and 1 are supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
CHECK_BITS_LEFT(7 + 1 + 4 + 9);
|
||||
uint32_t bitstream_version = mBitReader.getBits(7);
|
||||
mBitReader.skipBits(1); // fs_index
|
||||
mBitReader.skipBits(4); // frame_rate_index
|
||||
uint32_t n_presentations = mBitReader.getBits(9);
|
||||
|
||||
int32_t short_program_id = -1;
|
||||
if (bitstream_version > 1) {
|
||||
if (ac4_dsi_version == 0){
|
||||
ALOGE("invalid ac4 dsi");
|
||||
return false;
|
||||
}
|
||||
CHECK_BITS_LEFT(1);
|
||||
bool b_program_id = (mBitReader.getBits(1) == 1);
|
||||
if (b_program_id) {
|
||||
CHECK_BITS_LEFT(16 + 1);
|
||||
short_program_id = mBitReader.getBits(16);
|
||||
bool b_uuid = (mBitReader.getBits(1) == 1);
|
||||
if (b_uuid) {
|
||||
const uint32_t kAC4UUIDSizeInBytes = 16;
|
||||
char program_uuid[kAC4UUIDSizeInBytes];
|
||||
CHECK_BITS_LEFT(kAC4UUIDSizeInBytes * 8);
|
||||
for (uint32_t i = 0; i < kAC4UUIDSizeInBytes; i++) {
|
||||
program_uuid[i] = (char)(mBitReader.getBits(8));
|
||||
}
|
||||
ALOGV("UUID = %s", program_uuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ac4_dsi_version == 1) {
|
||||
if (!parseBitrateDsi()) {
|
||||
return false;
|
||||
}
|
||||
BYTE_ALIGN;
|
||||
}
|
||||
|
||||
for (uint32_t presentation = 0; presentation < n_presentations; presentation++) {
|
||||
mPresentations[presentation].mProgramID = short_program_id;
|
||||
// known as b_single_substream in ac4_dsi_version 0
|
||||
bool b_single_substream_group = false;
|
||||
uint32_t presentation_config = 0, presentation_version = 0;
|
||||
uint32_t pres_bytes = 0;
|
||||
|
||||
if (ac4_dsi_version == 0) {
|
||||
CHECK_BITS_LEFT(1 + 5 + 5);
|
||||
b_single_substream_group = (mBitReader.getBits(1) == 1);
|
||||
presentation_config = mBitReader.getBits(5);
|
||||
presentation_version = mBitReader.getBits(5);
|
||||
} else if (ac4_dsi_version == 1) {
|
||||
CHECK_BITS_LEFT(8 + 8);
|
||||
presentation_version = mBitReader.getBits(8);
|
||||
pres_bytes = mBitReader.getBits(8);
|
||||
if (pres_bytes == 0xff) {
|
||||
CHECK_BITS_LEFT(16);
|
||||
pres_bytes += mBitReader.getBits(16);
|
||||
}
|
||||
ALOGV("%u: pres_bytes = %u\n", presentation, pres_bytes);
|
||||
if (presentation_version > 1) {
|
||||
CHECK_BITS_LEFT(pres_bytes * 8);
|
||||
mBitReader.skipBits(pres_bytes * 8);
|
||||
continue;
|
||||
}
|
||||
// ac4_presentation_v0_dsi() and ac4_presentation_v1_dsi() both
|
||||
// start with a presentation_config of 5 bits
|
||||
CHECK_BITS_LEFT(5);
|
||||
presentation_config = mBitReader.getBits(5);
|
||||
b_single_substream_group = (presentation_config == 0x1f);
|
||||
}
|
||||
|
||||
static const char *PresentationConfig[] = {
|
||||
"Music&Effects + Dialog",
|
||||
"Main + DE",
|
||||
"Main + Associate",
|
||||
"Music&Effects + Dialog + Associate",
|
||||
"Main + DE + Associate",
|
||||
"Arbitrary substream groups",
|
||||
"EMDF only"
|
||||
};
|
||||
ALOGV("%u: b_single_substream/group = %s\n", presentation,
|
||||
BOOLSTR(b_single_substream_group));
|
||||
ALOGV("%u: presentation_version = %u\n", presentation, presentation_version);
|
||||
ALOGV("%u: presentation_config = %u (%s)\n", presentation, presentation_config,
|
||||
(presentation_config >= NELEM(PresentationConfig) ?
|
||||
"reserved" : PresentationConfig[presentation_config]));
|
||||
|
||||
/* record a marker, less the size of the presentation_config */
|
||||
uint64_t start = (mDSISize - mBitReader.numBitsLeft()) / 8;
|
||||
|
||||
bool b_add_emdf_substreams = false;
|
||||
if (!b_single_substream_group && presentation_config == 6) {
|
||||
b_add_emdf_substreams = true;
|
||||
ALOGV("%u: b_add_emdf_substreams = %s\n", presentation, BOOLSTR(b_add_emdf_substreams));
|
||||
} else {
|
||||
CHECK_BITS_LEFT(3 + 1);
|
||||
uint32_t mdcompat = mBitReader.getBits(3);
|
||||
ALOGV("%u: mdcompat = %d\n", presentation, mdcompat);
|
||||
|
||||
bool b_presentation_group_index = (mBitReader.getBits(1) == 1);
|
||||
ALOGV("%u: b_presentation_group_index = %s\n", presentation,
|
||||
BOOLSTR(b_presentation_group_index));
|
||||
if (b_presentation_group_index) {
|
||||
CHECK_BITS_LEFT(5);
|
||||
mPresentations[presentation].mGroupIndex = mBitReader.getBits(5);
|
||||
ALOGV("%u: presentation_group_index = %d\n", presentation,
|
||||
mPresentations[presentation].mGroupIndex);
|
||||
}
|
||||
CHECK_BITS_LEFT(2);
|
||||
uint32_t dsi_frame_rate_multiply_info = mBitReader.getBits(2);
|
||||
ALOGV("%u: dsi_frame_rate_multiply_info = %d\n", presentation,
|
||||
dsi_frame_rate_multiply_info);
|
||||
if (ac4_dsi_version == 1 && presentation_version == 1) {
|
||||
CHECK_BITS_LEFT(2);
|
||||
uint32_t dsi_frame_rate_fraction_info = mBitReader.getBits(2);
|
||||
ALOGV("%u: dsi_frame_rate_fraction_info = %d\n", presentation,
|
||||
dsi_frame_rate_fraction_info);
|
||||
}
|
||||
CHECK_BITS_LEFT(5 + 10);
|
||||
uint32_t presentation_emdf_version = mBitReader.getBits(5);
|
||||
uint32_t presentation_key_id = mBitReader.getBits(10);
|
||||
ALOGV("%u: presentation_emdf_version = %d\n", presentation, presentation_emdf_version);
|
||||
ALOGV("%u: presentation_key_id = %d\n", presentation, presentation_key_id);
|
||||
|
||||
if (ac4_dsi_version == 1) {
|
||||
bool b_presentation_channel_coded = false;
|
||||
if (presentation_version == 0) {
|
||||
b_presentation_channel_coded = true;
|
||||
} else {
|
||||
CHECK_BITS_LEFT(1);
|
||||
b_presentation_channel_coded = (mBitReader.getBits(1) == 1);
|
||||
}
|
||||
ALOGV("%u: b_presentation_channel_coded = %s\n", presentation,
|
||||
BOOLSTR(b_presentation_channel_coded));
|
||||
if (b_presentation_channel_coded) {
|
||||
if (presentation_version == 1) {
|
||||
CHECK_BITS_LEFT(5);
|
||||
uint32_t dsi_presentation_ch_mode = mBitReader.getBits(5);
|
||||
mPresentations[presentation].mChannelMode = dsi_presentation_ch_mode;
|
||||
ALOGV("%u: dsi_presentation_ch_mode = %d (%s)\n", presentation,
|
||||
dsi_presentation_ch_mode,
|
||||
dsi_presentation_ch_mode < NELEM(ChannelModes) ?
|
||||
ChannelModes[dsi_presentation_ch_mode] : "reserved");
|
||||
|
||||
if (dsi_presentation_ch_mode >= 11 && dsi_presentation_ch_mode <= 14) {
|
||||
CHECK_BITS_LEFT(1 + 2);
|
||||
uint32_t pres_b_4_back_channels_present = mBitReader.getBits(1);
|
||||
uint32_t pres_top_channel_pairs = mBitReader.getBits(2);
|
||||
ALOGV("%u: pres_b_4_back_channels_present = %s\n", presentation,
|
||||
BOOLSTR(pres_b_4_back_channels_present));
|
||||
ALOGV("%u: pres_top_channel_pairs = %d\n", presentation,
|
||||
pres_top_channel_pairs);
|
||||
}
|
||||
}
|
||||
// presentation_channel_mask in ac4_presentation_v0_dsi()
|
||||
CHECK_BITS_LEFT(24);
|
||||
uint32_t presentation_channel_mask_v1 = mBitReader.getBits(24);
|
||||
ALOGV("%u: presentation_channel_mask_v1 = 0x%06x\n", presentation,
|
||||
presentation_channel_mask_v1);
|
||||
}
|
||||
if (presentation_version == 1) {
|
||||
CHECK_BITS_LEFT(1);
|
||||
bool b_presentation_core_differs = (mBitReader.getBits(1) == 1);
|
||||
ALOGV("%u: b_presentation_core_differs = %s\n", presentation,
|
||||
BOOLSTR(b_presentation_core_differs));
|
||||
if (b_presentation_core_differs) {
|
||||
CHECK_BITS_LEFT(1);
|
||||
bool b_presentation_core_channel_coded = (mBitReader.getBits(1) == 1);
|
||||
if (b_presentation_core_channel_coded) {
|
||||
CHECK_BITS_LEFT(2);
|
||||
mBitReader.skipBits(2); // dsi_presentation_channel_mode_core
|
||||
}
|
||||
}
|
||||
CHECK_BITS_LEFT(1);
|
||||
bool b_presentation_filter = (mBitReader.getBits(1) == 1);
|
||||
ALOGV("%u: b_presentation_filter = %s\n", presentation,
|
||||
BOOLSTR(b_presentation_filter));
|
||||
if (b_presentation_filter) {
|
||||
CHECK_BITS_LEFT(1 + 8);
|
||||
bool b_enable_presentation = (mBitReader.getBits(1) == 1);
|
||||
if (!b_enable_presentation) {
|
||||
mPresentations[presentation].mEnabled = false;
|
||||
}
|
||||
ALOGV("%u: b_enable_presentation = %s\n", presentation,
|
||||
BOOLSTR(b_enable_presentation));
|
||||
uint32_t n_filter_bytes = mBitReader.getBits(8);
|
||||
CHECK_BITS_LEFT(n_filter_bytes * 8);
|
||||
for (uint32_t i = 0; i < n_filter_bytes; i++) {
|
||||
mBitReader.skipBits(8); // filter_data
|
||||
}
|
||||
}
|
||||
}
|
||||
} /* ac4_dsi_version == 1 */
|
||||
|
||||
if (b_single_substream_group) {
|
||||
if (presentation_version == 0) {
|
||||
if (!parseSubstreamDSI(presentation, 0)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!parseSubstreamGroupDSI(presentation, 0)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (ac4_dsi_version == 1) {
|
||||
CHECK_BITS_LEFT(1);
|
||||
bool b_multi_pid = (mBitReader.getBits(1) == 1);
|
||||
ALOGV("%u: b_multi_pid = %s\n", presentation, BOOLSTR(b_multi_pid));
|
||||
} else {
|
||||
CHECK_BITS_LEFT(1);
|
||||
bool b_hsf_ext = (mBitReader.getBits(1) == 1);
|
||||
ALOGV("%u: b_hsf_ext = %s\n", presentation, BOOLSTR(b_hsf_ext));
|
||||
}
|
||||
switch (presentation_config) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
if (presentation_version == 0) {
|
||||
if (!parseSubstreamDSI(presentation, 0)) {
|
||||
return false;
|
||||
}
|
||||
if (!parseSubstreamDSI(presentation, 1)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!parseSubstreamGroupDSI(presentation, 0)) {
|
||||
return false;
|
||||
}
|
||||
if (!parseSubstreamGroupDSI(presentation, 1)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
if (presentation_version == 0) {
|
||||
if (!parseSubstreamDSI(presentation, 0)) {
|
||||
return false;
|
||||
}
|
||||
if (!parseSubstreamDSI(presentation, 1)) {
|
||||
return false;
|
||||
}
|
||||
if (!parseSubstreamDSI(presentation, 2)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!parseSubstreamGroupDSI(presentation, 0)) {
|
||||
return false;
|
||||
}
|
||||
if (!parseSubstreamGroupDSI(presentation, 1)) {
|
||||
return false;
|
||||
}
|
||||
if (!parseSubstreamGroupDSI(presentation, 2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
if (presentation_version == 0) {
|
||||
if (!parseSubstreamDSI(presentation, 0)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
CHECK_BITS_LEFT(3);
|
||||
uint32_t n_substream_groups_minus2 = mBitReader.getBits(3);
|
||||
ALOGV("%u: n_substream_groups_minus2 = %d\n", presentation,
|
||||
n_substream_groups_minus2);
|
||||
for (uint32_t sg = 0; sg < n_substream_groups_minus2 + 2; sg++) {
|
||||
if (!parseSubstreamGroupDSI(presentation, sg)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
CHECK_BITS_LEFT(7);
|
||||
uint32_t n_skip_bytes = mBitReader.getBits(7);
|
||||
CHECK_BITS_LEFT(n_skip_bytes * 8)
|
||||
for (uint32_t j = 0; j < n_skip_bytes; j++) {
|
||||
mBitReader.getBits(8);
|
||||
}
|
||||
break;
|
||||
}
|
||||
CHECK_BITS_LEFT(1 + 1);
|
||||
bool b_pre_virtualized = (mBitReader.getBits(1) == 1);
|
||||
mPresentations[presentation].mPreVirtualized = b_pre_virtualized;
|
||||
b_add_emdf_substreams = (mBitReader.getBits(1) == 1);
|
||||
ALOGV("%u: b_pre_virtualized = %s\n", presentation, BOOLSTR(b_pre_virtualized));
|
||||
ALOGV("%u: b_add_emdf_substreams = %s\n", presentation,
|
||||
BOOLSTR(b_add_emdf_substreams));
|
||||
}
|
||||
}
|
||||
if (b_add_emdf_substreams) {
|
||||
CHECK_BITS_LEFT(7);
|
||||
uint32_t n_add_emdf_substreams = mBitReader.getBits(7);
|
||||
for (uint32_t j = 0; j < n_add_emdf_substreams; j++) {
|
||||
CHECK_BITS_LEFT(5 + 10);
|
||||
uint32_t substream_emdf_version = mBitReader.getBits(5);
|
||||
uint32_t substream_key_id = mBitReader.getBits(10);
|
||||
ALOGV("%u: emdf_substream[%d]: version=%d, key_id=%d\n", presentation, j,
|
||||
substream_emdf_version, substream_key_id);
|
||||
}
|
||||
}
|
||||
|
||||
bool b_presentation_bitrate_info = false;
|
||||
if (presentation_version > 0) {
|
||||
CHECK_BITS_LEFT(1);
|
||||
b_presentation_bitrate_info = (mBitReader.getBits(1) == 1);
|
||||
}
|
||||
|
||||
ALOGV("b_presentation_bitrate_info = %s\n", BOOLSTR(b_presentation_bitrate_info));
|
||||
if (b_presentation_bitrate_info) {
|
||||
if (!parseBitrateDsi()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (presentation_version > 0) {
|
||||
CHECK_BITS_LEFT(1);
|
||||
bool b_alternative = (mBitReader.getBits(1) == 1);
|
||||
ALOGV("b_alternative = %s\n", BOOLSTR(b_alternative));
|
||||
if (b_alternative) {
|
||||
BYTE_ALIGN;
|
||||
CHECK_BITS_LEFT(16);
|
||||
uint32_t name_len = mBitReader.getBits(16);
|
||||
char* presentation_name = new char[name_len+1];
|
||||
CHECK_BITS_LEFT(name_len * 8);
|
||||
for (uint32_t i = 0; i < name_len; i++) {
|
||||
presentation_name[i] = (char)(mBitReader.getBits(8));
|
||||
}
|
||||
presentation_name[name_len] = '\0';
|
||||
std::string description(presentation_name, name_len);
|
||||
mPresentations[presentation].mDescription = description;
|
||||
CHECK_BITS_LEFT(5);
|
||||
uint32_t n_targets = mBitReader.getBits(5);
|
||||
CHECK_BITS_LEFT(n_targets * (3 + 8));
|
||||
for (uint32_t i = 0; i < n_targets; i++){
|
||||
mBitReader.skipBits(3); // target_md_compat
|
||||
mBitReader.skipBits(8); // target_device_category
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BYTE_ALIGN;
|
||||
|
||||
if (ac4_dsi_version == 1) {
|
||||
uint64_t end = (mDSISize - mBitReader.numBitsLeft()) / 8;
|
||||
if (mBitReader.numBitsLeft() % 8 != 0) {
|
||||
end += 1;
|
||||
}
|
||||
|
||||
uint64_t presentation_bytes = end - start;
|
||||
uint64_t skip_bytes = pres_bytes - presentation_bytes;
|
||||
ALOGV("skipping = %" PRIu64 " bytes", skip_bytes);
|
||||
CHECK_BITS_LEFT(skip_bytes * 8);
|
||||
mBitReader.skipBits(skip_bytes * 8);
|
||||
}
|
||||
|
||||
// we should know this or something is probably wrong
|
||||
// with the bitstream (or we don't support it)
|
||||
if (mPresentations[presentation].mChannelMode == -1){
|
||||
ALOGE("could not determing channel mode of presentation %d", presentation);
|
||||
return false;
|
||||
}
|
||||
} /* each presentation */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef AC4_PARSER_H_
|
||||
#define AC4_PARSER_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include <media/stagefright/foundation/ABitReader.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
class AC4Parser {
|
||||
public:
|
||||
AC4Parser();
|
||||
virtual ~AC4Parser() { }
|
||||
|
||||
virtual bool parse() = 0;
|
||||
|
||||
struct AC4Presentation {
|
||||
int32_t mChannelMode = -1;
|
||||
int32_t mProgramID = -1;
|
||||
int32_t mGroupIndex = -1;
|
||||
|
||||
// TS 103 190-1 v1.2.1 4.3.3.8.1
|
||||
enum ContentClassifiers {
|
||||
kCompleteMain,
|
||||
kMusicAndEffects,
|
||||
kVisuallyImpaired,
|
||||
kHearingImpaired,
|
||||
kDialog,
|
||||
kCommentary,
|
||||
kEmergency,
|
||||
kVoiceOver
|
||||
};
|
||||
|
||||
uint32_t mContentClassifier = kCompleteMain;
|
||||
|
||||
// ETSI TS 103 190-2 V1.1.1 (2015-09) Table 79: channel_mode
|
||||
enum InputChannelMode {
|
||||
kChannelMode_Mono,
|
||||
kChannelMode_Stereo,
|
||||
kChannelMode_3_0,
|
||||
kChannelMode_5_0,
|
||||
kChannelMode_5_1,
|
||||
kChannelMode_7_0_34,
|
||||
kChannelMode_7_1_34,
|
||||
kChannelMode_7_0_52,
|
||||
kChannelMode_7_1_52,
|
||||
kChannelMode_7_0_322,
|
||||
kChannelMode_7_1_322,
|
||||
kChannelMode_7_0_4,
|
||||
kChannelMode_7_1_4,
|
||||
kChannelMode_9_0_4,
|
||||
kChannelMode_9_1_4,
|
||||
kChannelMode_22_2,
|
||||
kChannelMode_Reserved,
|
||||
};
|
||||
|
||||
bool mHasDialogEnhancements = false;
|
||||
bool mPreVirtualized = false;
|
||||
bool mEnabled = true;
|
||||
|
||||
std::string mLanguage;
|
||||
std::string mDescription;
|
||||
};
|
||||
typedef std::map<uint32_t, AC4Presentation> AC4Presentations;
|
||||
|
||||
const AC4Presentations& getPresentations() const { return mPresentations; }
|
||||
|
||||
protected:
|
||||
AC4Presentations mPresentations;
|
||||
};
|
||||
|
||||
class AC4DSIParser: public AC4Parser {
|
||||
public:
|
||||
explicit AC4DSIParser(ABitReader &br);
|
||||
virtual ~AC4DSIParser() { }
|
||||
|
||||
bool parse();
|
||||
|
||||
private:
|
||||
bool parseSubstreamDSI(uint32_t presentationID, uint32_t substreamID);
|
||||
bool parseSubstreamGroupDSI(uint32_t presentationID, uint32_t groupID);
|
||||
bool parseLanguageTag(uint32_t presentationID, uint32_t substreamID);
|
||||
bool parseBitrateDsi();
|
||||
|
||||
uint64_t mDSISize;
|
||||
ABitReader& mBitReader;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif // AC4_PARSER_H_
|
Loading…
Reference in new issue