am f0ad5484: Merge "In the absence of width/height information in the sdp, extract the dimensions from the avc codec specific data." into gingerbread
Merge commit 'f0ad54846168f07fc1fd7f18cde93deea1559f86' into gingerbread-plus-aosp * commit 'f0ad54846168f07fc1fd7f18cde93deea1559f86': In the absence of width/height information in the sdp, extract the dimensions from the avc codec specific data.
This commit is contained in:
@@ -39,6 +39,7 @@ LOCAL_SRC_FILES:= \
|
||||
TimedEventQueue.cpp \
|
||||
Utils.cpp \
|
||||
WAVExtractor.cpp \
|
||||
avc_utils.cpp \
|
||||
string.cpp
|
||||
|
||||
LOCAL_C_INCLUDES:= \
|
||||
|
||||
91
media/libstagefright/avc_utils.cpp
Normal file
91
media/libstagefright/avc_utils.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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.
|
||||
*/
|
||||
|
||||
#include "include/avc_utils.h"
|
||||
|
||||
#include <media/stagefright/foundation/ABitReader.h>
|
||||
#include <media/stagefright/foundation/ADebug.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
static unsigned parseUE(ABitReader *br) {
|
||||
unsigned numZeroes = 0;
|
||||
while (br->getBits(1) == 0) {
|
||||
++numZeroes;
|
||||
}
|
||||
|
||||
unsigned x = br->getBits(numZeroes);
|
||||
|
||||
return x + (1u << numZeroes) - 1;
|
||||
}
|
||||
|
||||
// Determine video dimensions from the sequence parameterset.
|
||||
void FindAVCDimensions(
|
||||
const sp<ABuffer> &seqParamSet, int32_t *width, int32_t *height) {
|
||||
ABitReader br(seqParamSet->data() + 1, seqParamSet->size() - 1);
|
||||
|
||||
unsigned profile_idc = br.getBits(8);
|
||||
br.skipBits(16);
|
||||
parseUE(&br); // seq_parameter_set_id
|
||||
|
||||
if (profile_idc == 100 || profile_idc == 110
|
||||
|| profile_idc == 122 || profile_idc == 244
|
||||
|| profile_idc == 44 || profile_idc == 83 || profile_idc == 86) {
|
||||
unsigned chroma_format_idc = parseUE(&br);
|
||||
if (chroma_format_idc == 3) {
|
||||
br.skipBits(1); // residual_colour_transform_flag
|
||||
}
|
||||
parseUE(&br); // bit_depth_luma_minus8
|
||||
parseUE(&br); // bit_depth_chroma_minus8
|
||||
br.skipBits(1); // qpprime_y_zero_transform_bypass_flag
|
||||
CHECK_EQ(br.getBits(1), 0u); // seq_scaling_matrix_present_flag
|
||||
}
|
||||
|
||||
parseUE(&br); // log2_max_frame_num_minus4
|
||||
unsigned pic_order_cnt_type = parseUE(&br);
|
||||
|
||||
if (pic_order_cnt_type == 0) {
|
||||
parseUE(&br); // log2_max_pic_order_cnt_lsb_minus4
|
||||
} else if (pic_order_cnt_type == 1) {
|
||||
// offset_for_non_ref_pic, offset_for_top_to_bottom_field and
|
||||
// offset_for_ref_frame are technically se(v), but since we are
|
||||
// just skipping over them the midpoint does not matter.
|
||||
|
||||
br.getBits(1); // delta_pic_order_always_zero_flag
|
||||
parseUE(&br); // offset_for_non_ref_pic
|
||||
parseUE(&br); // offset_for_top_to_bottom_field
|
||||
|
||||
unsigned num_ref_frames_in_pic_order_cnt_cycle = parseUE(&br);
|
||||
for (unsigned i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; ++i) {
|
||||
parseUE(&br); // offset_for_ref_frame
|
||||
}
|
||||
}
|
||||
|
||||
parseUE(&br); // num_ref_frames
|
||||
br.getBits(1); // gaps_in_frame_num_value_allowed_flag
|
||||
|
||||
unsigned pic_width_in_mbs_minus1 = parseUE(&br);
|
||||
unsigned pic_height_in_map_units_minus1 = parseUE(&br);
|
||||
unsigned frame_mbs_only_flag = br.getBits(1);
|
||||
|
||||
*width = pic_width_in_mbs_minus1 * 16 + 16;
|
||||
|
||||
*height = (2 - frame_mbs_only_flag)
|
||||
* (pic_height_in_map_units_minus1 * 16 + 16);
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
|
||||
@@ -3,6 +3,7 @@ include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES:= \
|
||||
AAtomizer.cpp \
|
||||
ABitReader.cpp \
|
||||
ABuffer.cpp \
|
||||
ADebug.cpp \
|
||||
AHandler.cpp \
|
||||
|
||||
30
media/libstagefright/include/avc_utils.h
Normal file
30
media/libstagefright/include/avc_utils.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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 AVC_UTILS_H_
|
||||
|
||||
#define AVC_UTILS_H_
|
||||
|
||||
#include <media/stagefright/foundation/ABuffer.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
void FindAVCDimensions(
|
||||
const sp<ABuffer> &seqParamSet, int32_t *width, int32_t *height);
|
||||
|
||||
} // namespace android
|
||||
|
||||
#endif // AVC_UTILS_H_
|
||||
@@ -16,9 +16,10 @@
|
||||
|
||||
#include "ATSParser.h"
|
||||
|
||||
#include "ABitReader.h"
|
||||
#include "AnotherPacketSource.h"
|
||||
#include "include/avc_utils.h"
|
||||
|
||||
#include <media/stagefright/foundation/ABitReader.h>
|
||||
#include <media/stagefright/foundation/ABuffer.h>
|
||||
#include <media/stagefright/foundation/ADebug.h>
|
||||
#include <media/stagefright/foundation/AMessage.h>
|
||||
@@ -473,60 +474,6 @@ static sp<ABuffer> FindNAL(
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned parseUE(ABitReader *br) {
|
||||
unsigned numZeroes = 0;
|
||||
while (br->getBits(1) == 0) {
|
||||
++numZeroes;
|
||||
}
|
||||
|
||||
unsigned x = br->getBits(numZeroes);
|
||||
|
||||
return x + (1u << numZeroes) - 1;
|
||||
}
|
||||
|
||||
// Determine video dimensions from the sequence parameterset.
|
||||
static void FindDimensions(
|
||||
const sp<ABuffer> seqParamSet, int32_t *width, int32_t *height) {
|
||||
ABitReader br(seqParamSet->data() + 1, seqParamSet->size() - 1);
|
||||
|
||||
unsigned profile_idc = br.getBits(8);
|
||||
br.skipBits(16);
|
||||
parseUE(&br); // seq_parameter_set_id
|
||||
|
||||
if (profile_idc == 100 || profile_idc == 110
|
||||
|| profile_idc == 122 || profile_idc == 144) {
|
||||
TRESPASS();
|
||||
}
|
||||
|
||||
parseUE(&br); // log2_max_frame_num_minus4
|
||||
unsigned pic_order_cnt_type = parseUE(&br);
|
||||
|
||||
if (pic_order_cnt_type == 0) {
|
||||
parseUE(&br); // log2_max_pic_order_cnt_lsb_minus4
|
||||
} else if (pic_order_cnt_type == 1) {
|
||||
br.getBits(1); // delta_pic_order_always_zero_flag
|
||||
parseUE(&br); // offset_for_non_ref_pic
|
||||
parseUE(&br); // offset_for_top_to_bottom_field
|
||||
|
||||
unsigned num_ref_frames_in_pic_order_cnt_cycle = parseUE(&br);
|
||||
for (unsigned i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; ++i) {
|
||||
parseUE(&br); // offset_for_ref_frame
|
||||
}
|
||||
}
|
||||
|
||||
parseUE(&br); // num_ref_frames
|
||||
br.getBits(1); // gaps_in_frame_num_value_allowed_flag
|
||||
|
||||
unsigned pic_width_in_mbs_minus1 = parseUE(&br);
|
||||
unsigned pic_height_in_map_units_minus1 = parseUE(&br);
|
||||
unsigned frame_mbs_only_flag = br.getBits(1);
|
||||
|
||||
*width = pic_width_in_mbs_minus1 * 16 + 16;
|
||||
|
||||
*height = (2 - frame_mbs_only_flag)
|
||||
* (pic_height_in_map_units_minus1 * 16 + 16);
|
||||
}
|
||||
|
||||
static sp<ABuffer> MakeAVCCodecSpecificData(
|
||||
const sp<ABuffer> &buffer, int32_t *width, int32_t *height) {
|
||||
const uint8_t *data = buffer->data();
|
||||
@@ -537,7 +484,7 @@ static sp<ABuffer> MakeAVCCodecSpecificData(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FindDimensions(seqParamSet, width, height);
|
||||
FindAVCDimensions(seqParamSet, width, height);
|
||||
|
||||
size_t stopOffset;
|
||||
sp<ABuffer> picParamSet = FindNAL(data, size, 8, &stopOffset);
|
||||
|
||||
@@ -3,7 +3,6 @@ LOCAL_PATH:= $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES:= \
|
||||
ABitReader.cpp \
|
||||
AnotherPacketSource.cpp \
|
||||
ATSParser.cpp \
|
||||
MPEG2TSExtractor.cpp \
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
#include "ASessionDescription.h"
|
||||
|
||||
#include "avc_utils.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include <media/stagefright/foundation/ABuffer.h>
|
||||
@@ -96,7 +98,11 @@ static sp<ABuffer> decodeHex(const AString &s) {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static sp<ABuffer> MakeAVCCodecSpecificData(const char *params) {
|
||||
static sp<ABuffer> MakeAVCCodecSpecificData(
|
||||
const char *params, int32_t *width, int32_t *height) {
|
||||
*width = 0;
|
||||
*height = 0;
|
||||
|
||||
AString val;
|
||||
if (!GetAttribute(params, "profile-level-id", &val)) {
|
||||
return NULL;
|
||||
@@ -178,6 +184,11 @@ static sp<ABuffer> MakeAVCCodecSpecificData(const char *params) {
|
||||
memcpy(out, nal->data(), nal->size());
|
||||
|
||||
out += nal->size();
|
||||
|
||||
if (i == 0) {
|
||||
FindAVCDimensions(nal, width, height);
|
||||
LOG(INFO) << "dimensions " << *width << "x" << *height;
|
||||
}
|
||||
}
|
||||
|
||||
*out++ = numPicParameterSets;
|
||||
@@ -193,7 +204,7 @@ static sp<ABuffer> MakeAVCCodecSpecificData(const char *params) {
|
||||
out += nal->size();
|
||||
}
|
||||
|
||||
hexdump(csd->data(), csd->size());
|
||||
// hexdump(csd->data(), csd->size());
|
||||
|
||||
return csd;
|
||||
}
|
||||
@@ -230,7 +241,7 @@ sp<ABuffer> MakeAACCodecSpecificData(const char *params) {
|
||||
csd->data()[sizeof(kStaticESDS)] = (x >> 8) & 0xff;
|
||||
csd->data()[sizeof(kStaticESDS) + 1] = x & 0xff;
|
||||
|
||||
hexdump(csd->data(), csd->size());
|
||||
// hexdump(csd->data(), csd->size());
|
||||
|
||||
return csd;
|
||||
}
|
||||
@@ -260,22 +271,32 @@ APacketSource::APacketSource(
|
||||
|
||||
int32_t width, height;
|
||||
if (!sessionDesc->getDimensions(index, PT, &width, &height)) {
|
||||
// TODO: extract dimensions from sequence parameter set.
|
||||
width = -1;
|
||||
height = -1;
|
||||
}
|
||||
|
||||
int32_t encWidth, encHeight;
|
||||
sp<ABuffer> codecSpecificData =
|
||||
MakeAVCCodecSpecificData(params.c_str(), &encWidth, &encHeight);
|
||||
|
||||
if (codecSpecificData != NULL) {
|
||||
if (width < 0) {
|
||||
// If no explicit width/height given in the sdp, use the dimensions
|
||||
// extracted from the first sequence parameter set.
|
||||
width = encWidth;
|
||||
height = encHeight;
|
||||
}
|
||||
|
||||
mFormat->setData(
|
||||
kKeyAVCC, 0,
|
||||
codecSpecificData->data(), codecSpecificData->size());
|
||||
} else if (width < 0) {
|
||||
mInitCheck = ERROR_UNSUPPORTED;
|
||||
return;
|
||||
}
|
||||
|
||||
mFormat->setInt32(kKeyWidth, width);
|
||||
mFormat->setInt32(kKeyHeight, height);
|
||||
|
||||
sp<ABuffer> codecSpecificData =
|
||||
MakeAVCCodecSpecificData(params.c_str());
|
||||
|
||||
if (codecSpecificData != NULL) {
|
||||
mFormat->setData(
|
||||
kKeyAVCC, 0,
|
||||
codecSpecificData->data(), codecSpecificData->size());
|
||||
}
|
||||
} else if (!strncmp(desc.c_str(), "H263-2000/", 10)
|
||||
|| !strncmp(desc.c_str(), "H263-1998/", 10)) {
|
||||
mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
|
||||
|
||||
Reference in New Issue
Block a user