From 85f12e9b9062402d6110df3f7099707912040edb Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Thu, 19 Aug 2010 10:39:47 -0700 Subject: In the absence of width/height information in the sdp, extract the dimensions from the avc codec specific data. Change-Id: I98c4194593c7e6e24f6fc339c862245111800293 --- include/media/stagefright/foundation/ABitReader.h | 53 ++++++++++++ media/libstagefright/Android.mk | 1 + media/libstagefright/avc_utils.cpp | 91 +++++++++++++++++++++ media/libstagefright/foundation/ABitReader.cpp | 98 +++++++++++++++++++++++ media/libstagefright/foundation/Android.mk | 1 + media/libstagefright/include/avc_utils.h | 30 +++++++ media/libstagefright/mpeg2ts/ABitReader.cpp | 98 ----------------------- media/libstagefright/mpeg2ts/ABitReader.h | 53 ------------ media/libstagefright/mpeg2ts/ATSParser.cpp | 59 +------------- media/libstagefright/mpeg2ts/Android.mk | 1 - media/libstagefright/rtsp/APacketSource.cpp | 41 +++++++--- 11 files changed, 308 insertions(+), 218 deletions(-) create mode 100644 include/media/stagefright/foundation/ABitReader.h create mode 100644 media/libstagefright/avc_utils.cpp create mode 100644 media/libstagefright/foundation/ABitReader.cpp create mode 100644 media/libstagefright/include/avc_utils.h delete mode 100644 media/libstagefright/mpeg2ts/ABitReader.cpp delete mode 100644 media/libstagefright/mpeg2ts/ABitReader.h diff --git a/include/media/stagefright/foundation/ABitReader.h b/include/media/stagefright/foundation/ABitReader.h new file mode 100644 index 0000000..5135211 --- /dev/null +++ b/include/media/stagefright/foundation/ABitReader.h @@ -0,0 +1,53 @@ +/* + * 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 A_BIT_READER_H_ + +#define A_BIT_READER_H_ + +#include + +#include +#include + +namespace android { + +struct ABitReader { + ABitReader(const uint8_t *data, size_t size); + + uint32_t getBits(size_t n); + void skipBits(size_t n); + + size_t numBitsLeft() const; + + const uint8_t *data() const; + +private: + const uint8_t *mData; + size_t mSize; + + uint32_t mReservoir; // left-aligned bits + size_t mNumBitsLeft; + + void fillReservoir(); + void putBits(uint32_t x, size_t n); + + DISALLOW_EVIL_CONSTRUCTORS(ABitReader); +}; + +} // namespace android + +#endif // A_BIT_READER_H_ diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index b8b2f3f..86fa668 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -39,6 +39,7 @@ LOCAL_SRC_FILES:= \ TimedEventQueue.cpp \ Utils.cpp \ WAVExtractor.cpp \ + avc_utils.cpp \ string.cpp LOCAL_C_INCLUDES:= \ diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp new file mode 100644 index 0000000..511ae12 --- /dev/null +++ b/media/libstagefright/avc_utils.cpp @@ -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 +#include + +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 &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 + diff --git a/media/libstagefright/foundation/ABitReader.cpp b/media/libstagefright/foundation/ABitReader.cpp new file mode 100644 index 0000000..24c8df8 --- /dev/null +++ b/media/libstagefright/foundation/ABitReader.cpp @@ -0,0 +1,98 @@ +/* + * 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 "ABitReader.h" + +#include + +namespace android { + +ABitReader::ABitReader(const uint8_t *data, size_t size) + : mData(data), + mSize(size), + mReservoir(0), + mNumBitsLeft(0) { +} + +void ABitReader::fillReservoir() { + CHECK_GT(mSize, 0u); + + mReservoir = 0; + size_t i; + for (i = 0; mSize > 0 && i < 4; ++i) { + mReservoir = (mReservoir << 8) | *mData; + + ++mData; + --mSize; + } + + mNumBitsLeft = 8 * i; + mReservoir <<= 32 - mNumBitsLeft; +} + +uint32_t ABitReader::getBits(size_t n) { + CHECK_LE(n, 32u); + + uint32_t result = 0; + while (n > 0) { + if (mNumBitsLeft == 0) { + fillReservoir(); + } + + size_t m = n; + if (m > mNumBitsLeft) { + m = mNumBitsLeft; + } + + result = (result << m) | (mReservoir >> (32 - m)); + mReservoir <<= m; + mNumBitsLeft -= m; + + n -= m; + } + + return result; +} + +void ABitReader::skipBits(size_t n) { + while (n > 32) { + getBits(32); + n -= 32; + } + + if (n > 0) { + getBits(n); + } +} + +void ABitReader::putBits(uint32_t x, size_t n) { + CHECK_LE(mNumBitsLeft + n, 32u); + + mReservoir = (mReservoir >> n) | (x << (32 - n)); + mNumBitsLeft += n; +} + +size_t ABitReader::numBitsLeft() const { + return mSize * 8 + mNumBitsLeft; +} + +const uint8_t *ABitReader::data() const { + CHECK_EQ(mNumBitsLeft % 8, 0u); + + return mData - mNumBitsLeft / 8; +} + +} // namespace android diff --git a/media/libstagefright/foundation/Android.mk b/media/libstagefright/foundation/Android.mk index 35eea7e..f6a8a52 100644 --- a/media/libstagefright/foundation/Android.mk +++ b/media/libstagefright/foundation/Android.mk @@ -3,6 +3,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ AAtomizer.cpp \ + ABitReader.cpp \ ABuffer.cpp \ ADebug.cpp \ AHandler.cpp \ diff --git a/media/libstagefright/include/avc_utils.h b/media/libstagefright/include/avc_utils.h new file mode 100644 index 0000000..cc405b5 --- /dev/null +++ b/media/libstagefright/include/avc_utils.h @@ -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 + +namespace android { + +void FindAVCDimensions( + const sp &seqParamSet, int32_t *width, int32_t *height); + +} // namespace android + +#endif // AVC_UTILS_H_ diff --git a/media/libstagefright/mpeg2ts/ABitReader.cpp b/media/libstagefright/mpeg2ts/ABitReader.cpp deleted file mode 100644 index 24c8df8..0000000 --- a/media/libstagefright/mpeg2ts/ABitReader.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* - * 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 "ABitReader.h" - -#include - -namespace android { - -ABitReader::ABitReader(const uint8_t *data, size_t size) - : mData(data), - mSize(size), - mReservoir(0), - mNumBitsLeft(0) { -} - -void ABitReader::fillReservoir() { - CHECK_GT(mSize, 0u); - - mReservoir = 0; - size_t i; - for (i = 0; mSize > 0 && i < 4; ++i) { - mReservoir = (mReservoir << 8) | *mData; - - ++mData; - --mSize; - } - - mNumBitsLeft = 8 * i; - mReservoir <<= 32 - mNumBitsLeft; -} - -uint32_t ABitReader::getBits(size_t n) { - CHECK_LE(n, 32u); - - uint32_t result = 0; - while (n > 0) { - if (mNumBitsLeft == 0) { - fillReservoir(); - } - - size_t m = n; - if (m > mNumBitsLeft) { - m = mNumBitsLeft; - } - - result = (result << m) | (mReservoir >> (32 - m)); - mReservoir <<= m; - mNumBitsLeft -= m; - - n -= m; - } - - return result; -} - -void ABitReader::skipBits(size_t n) { - while (n > 32) { - getBits(32); - n -= 32; - } - - if (n > 0) { - getBits(n); - } -} - -void ABitReader::putBits(uint32_t x, size_t n) { - CHECK_LE(mNumBitsLeft + n, 32u); - - mReservoir = (mReservoir >> n) | (x << (32 - n)); - mNumBitsLeft += n; -} - -size_t ABitReader::numBitsLeft() const { - return mSize * 8 + mNumBitsLeft; -} - -const uint8_t *ABitReader::data() const { - CHECK_EQ(mNumBitsLeft % 8, 0u); - - return mData - mNumBitsLeft / 8; -} - -} // namespace android diff --git a/media/libstagefright/mpeg2ts/ABitReader.h b/media/libstagefright/mpeg2ts/ABitReader.h deleted file mode 100644 index 5135211..0000000 --- a/media/libstagefright/mpeg2ts/ABitReader.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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 A_BIT_READER_H_ - -#define A_BIT_READER_H_ - -#include - -#include -#include - -namespace android { - -struct ABitReader { - ABitReader(const uint8_t *data, size_t size); - - uint32_t getBits(size_t n); - void skipBits(size_t n); - - size_t numBitsLeft() const; - - const uint8_t *data() const; - -private: - const uint8_t *mData; - size_t mSize; - - uint32_t mReservoir; // left-aligned bits - size_t mNumBitsLeft; - - void fillReservoir(); - void putBits(uint32_t x, size_t n); - - DISALLOW_EVIL_CONSTRUCTORS(ABitReader); -}; - -} // namespace android - -#endif // A_BIT_READER_H_ diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp index d05975d..26a0fb3 100644 --- a/media/libstagefright/mpeg2ts/ATSParser.cpp +++ b/media/libstagefright/mpeg2ts/ATSParser.cpp @@ -16,9 +16,10 @@ #include "ATSParser.h" -#include "ABitReader.h" #include "AnotherPacketSource.h" +#include "include/avc_utils.h" +#include #include #include #include @@ -473,60 +474,6 @@ static sp 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 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 MakeAVCCodecSpecificData( const sp &buffer, int32_t *width, int32_t *height) { const uint8_t *data = buffer->data(); @@ -537,7 +484,7 @@ static sp MakeAVCCodecSpecificData( return NULL; } - FindDimensions(seqParamSet, width, height); + FindAVCDimensions(seqParamSet, width, height); size_t stopOffset; sp picParamSet = FindNAL(data, size, 8, &stopOffset); diff --git a/media/libstagefright/mpeg2ts/Android.mk b/media/libstagefright/mpeg2ts/Android.mk index b6772eb..3544b4c 100644 --- a/media/libstagefright/mpeg2ts/Android.mk +++ b/media/libstagefright/mpeg2ts/Android.mk @@ -3,7 +3,6 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ - ABitReader.cpp \ AnotherPacketSource.cpp \ ATSParser.cpp \ MPEG2TSExtractor.cpp \ diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp index b2d697b..353c746 100644 --- a/media/libstagefright/rtsp/APacketSource.cpp +++ b/media/libstagefright/rtsp/APacketSource.cpp @@ -18,6 +18,8 @@ #include "ASessionDescription.h" +#include "avc_utils.h" + #include #include @@ -96,7 +98,11 @@ static sp decodeHex(const AString &s) { return buffer; } -static sp MakeAVCCodecSpecificData(const char *params) { +static sp 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 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 MakeAVCCodecSpecificData(const char *params) { out += nal->size(); } - hexdump(csd->data(), csd->size()); + // hexdump(csd->data(), csd->size()); return csd; } @@ -230,7 +241,7 @@ sp 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. - mInitCheck = ERROR_UNSUPPORTED; - return; + width = -1; + height = -1; } - mFormat->setInt32(kKeyWidth, width); - mFormat->setInt32(kKeyHeight, height); - + int32_t encWidth, encHeight; sp codecSpecificData = - MakeAVCCodecSpecificData(params.c_str()); + 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); } else if (!strncmp(desc.c_str(), "H263-2000/", 10) || !strncmp(desc.c_str(), "H263-1998/", 10)) { mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263); -- cgit v1.1