Well, actually i do not decode h264 stream but just need width, height info...
For h264 stream, here is simple buggy parser which gets width height from fSpropParameterSets... Maybe someone also need a starting point for parsing those data... Best Wishes How To Use: So in desribe response if you get those parmeters from scs.subsession->fmtp_spropparametersets(); just use this simple buggy parser like H264SPropParameterSetParser parser(scs.subsession->fmtp_spropparametersets()); int w = parse->GetWidth(); int h= parser->GetHeight(); Here is the codes: There is 2 class BitStreamReader, and H264SPropParameterSetParser // H264SPropParameterSetParser #pragma once #ifndef _H264_SPROP_PARAMETER_SET_PARSER_ #define _H264_SPROP_PARAMETER_SET_PARSER_ #include <iostream> #include "BitStreamReader.h" using namespace std; static const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789+/"; class H264SPropParameterSetParser { public: H264SPropParameterSetParser(string spsFromSdp) { this->spsFromSdp = spsFromSdp; height = 0; width = 0; StartParsing(); } int GetWidth() { int width = ( pic_width_in_mbs_minus1 +1)*16; return width; } int GetHeight() { int height =( pic_height_in_map_units_minus1+1)*16; return height; } ~H264SPropParameterSetParser(void) { delete bitStreamReader; bitStreamReader = NULL; } private: void StartParsing() { ConvertFromBase64IntoByteArray(); ParseSequenceParameterSet(); } void ConvertFromBase64IntoByteArray() { string decodedString = DecodeBase64( spsFromSdp); binaryData = new unsigned char[decodedString.size()]; std::copy(decodedString.begin(), decodedString.end(), binaryData); } void ParseSequenceParameterSet() { unsigned __int32 temp; bitStreamReader = new BitStreamReader(binaryData); bitStreamReader->U(8); // skip nal unit type profile_idc = bitStreamReader->U(8); constraint_set0_flag = bitStreamReader->U(1); constraint_set1_flag = bitStreamReader->U(1); constraint_set2_flag = bitStreamReader->U(1); constraint_set3_flag = bitStreamReader->U(1); reserved_zero_4bits = bitStreamReader->U(4); level_idc = bitStreamReader->U(8); seq_parameter_set_id = bitStreamReader->Uev(); if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122 || profile_idc == 144) { chroma_format_idc = bitStreamReader->Uev(); if (chroma_format_idc == 3) { separate_colour_plane_flag = bitStreamReader->U(1); } bit_depth_luma_minus8 = bitStreamReader->Uev(); bit_depth_chroma_minus8 = bitStreamReader->Uev(); qpprime_y_zero_transform_bypass_flag = bitStreamReader->U(1); seq_scaling_matrix_present_flag = bitStreamReader->U(1); if( seq_scaling_matrix_present_flag ) { for(unsigned int ix = 0; ix < 8; ix++) { temp = bitStreamReader->U(1); if (temp) { ScalingList(ix, ix < 6 ? 16 : 64); } } } } log2_max_frame_num_minus4 = bitStreamReader->Uev(); pic_order_cnt_type = bitStreamReader->Uev(); if (pic_order_cnt_type == 0) { log2_max_pic_order_cnt_lsb_minus4 = bitStreamReader->Uev(); } else if (pic_order_cnt_type == 1) { delta_pic_order_always_zero_flag = bitStreamReader->U(1); offset_for_non_ref_pic = bitStreamReader->Sev(); offset_for_top_to_bottom_field = bitStreamReader->Sev(); num_ref_frames_in_pic_order_cnt_cycle = bitStreamReader->Uev(); for( int i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++ ) { int skippedParameter = bitStreamReader->Sev(); } } num_ref_frames = bitStreamReader->Uev(); gaps_in_frame_num_value_allowed_flag = bitStreamReader->U(1); pic_width_in_mbs_minus1 = bitStreamReader->Uev(); pic_height_in_map_units_minus1 = bitStreamReader->Uev(); frame_mbs_only_flag = bitStreamReader->U(1); if( !frame_mbs_only_flag ) { mb_adaptive_frame_field_flag = bitStreamReader->U(1); } direct_8x8_inference_flag = bitStreamReader->U(1); frame_cropping_flag = bitStreamReader->U(1); if( frame_cropping_flag ) { frame_crop_left_offset = bitStreamReader->Uev(); frame_crop_right_offset = bitStreamReader->Uev(); frame_crop_top_offset = bitStreamReader->Uev(); frame_crop_bottom_offset = bitStreamReader->Uev(); } vui_parameters_present_flag = bitStreamReader->U(1); } // Utility to parse void ScalingList(unsigned int ix, unsigned int sizeOfScalingList) { unsigned int lastScale = 8; unsigned int nextScale = 8; unsigned int jx; int deltaScale; for (jx = 0; jx < sizeOfScalingList; jx++) { if (nextScale != 0) { deltaScale = bitStreamReader->Sev(); nextScale = (lastScale + deltaScale + 256) % 256; } if (nextScale == 0) { lastScale = lastScale; } else { lastScale = nextScale; } } } std::string DecodeBase64(std::string const& encodedString) { int inlen = encodedString.size(); int i = 0; int j = 0; int in = 0; unsigned char charArray4[4], charArray3[3]; std::string ret; while (inlen-- && ( encodedString[in] != '=') && IsBase64(encodedString[in])) { charArray4[i++] = encodedString[in]; in++; if (i ==4) { for (i = 0; i <4; i++) charArray4[i] = base64_chars.find(charArray4[i]); charArray3[0] = (charArray4[0] << 2) + ((charArray4[1] & 0x30) >> 4); charArray3[1] = ((charArray4[1] & 0xf) << 4) + ((charArray4[2] & 0x3c) >> 2); charArray3[2] = ((charArray4[2] & 0x3) << 6) + charArray4[3]; for (i = 0; (i < 3); i++) ret += charArray3[i]; i = 0; } } if (i) { for (j = i; j <4; j++) charArray4[j] = 0; for (j = 0; j <4; j++) charArray4[j] = base64_chars.find(charArray4[j]); charArray3[0] = (charArray4[0] << 2) + ((charArray4[1] & 0x30) >> 4); charArray3[1] = ((charArray4[1] & 0xf) << 4) + ((charArray4[2] & 0x3c) >> 2); charArray3[2] = ((charArray4[2] & 0x3) << 6) + charArray4[3]; for (j = 0; (j < i - 1); j++) ret += charArray3[j]; } return ret; } bool IsBase64(unsigned char c) { return (isalnum(c) || (c == '+') || (c == '/')); } // Data to Parse unsigned char* binaryData; // Parameter from Describe RtspReponse: Base64 string string spsFromSdp; // Utility to read bits esaily BitStreamReader* bitStreamReader; // Parameters int profile_idc ; int constraint_set0_flag; int constraint_set1_flag; int constraint_set2_flag; int constraint_set3_flag; int reserved_zero_4bits; int level_idc; int seq_parameter_set_id; int chroma_format_idc; int separate_colour_plane_flag; int bit_depth_luma_minus8; int bit_depth_chroma_minus8; int qpprime_y_zero_transform_bypass_flag; int seq_scaling_matrix_present_flag; int log2_max_frame_num_minus4; int pic_order_cnt_type; int log2_max_pic_order_cnt_lsb_minus4; int delta_pic_order_always_zero_flag; int offset_for_non_ref_pic; int offset_for_top_to_bottom_field; int num_ref_frames_in_pic_order_cnt_cycle; int num_ref_frames; int gaps_in_frame_num_value_allowed_flag; unsigned __int32 pic_width_in_mbs_minus1; unsigned __int32 pic_height_in_map_units_minus1; int frame_mbs_only_flag; int mb_adaptive_frame_field_flag; int direct_8x8_inference_flag; int frame_cropping_flag; int frame_crop_left_offset; int frame_crop_right_offset; int frame_crop_top_offset; int frame_crop_bottom_offset; int vui_parameters_present_flag; int height; int width; }; #endif Then // BitStreamReader #pragma once #ifndef __BIT_STREAM_READER__ #define __BIT_STREAM_READER__ #include <iostream> #include <sstream> #include <string> class BitStreamReader { public: BitStreamReader(unsigned char* dataToRead) { position = 0; binaryData = dataToRead; } ~BitStreamReader(void) { delete[] binaryData; binaryData = NULL; } void SkipBits(int n) { for (int i = 0; i < n; i++) { SkipBit(); } } int GetBits(int n) // Same as U(int n) { int result = 0; for (int i = 0; i < n; i++) { result = result * 2 +GetBit(); } return result; } int U(int n) { int result = 0; for (int i = 0; i < n; i++) { result = result * 2 +GetBit(); } return result; } int Uev() { return Ev(false); } int Sev() { return Ev(true); } private: int GetBit() { int mask = 1 << (7 - (position & 7)); int index = position >> 3; position++; return ((binaryData[index] & mask) == 0) ? 0 : 1; } void SkipBit() { position++; } int Ev(bool isItSigned) { int bitCount = 0; std::string expGolomb; while (GetBit() == 0) { expGolomb += '0'; bitCount++; } expGolomb += "/1"; int result = 1; for (int i = 0; i < bitCount; i++) { int b = GetBit(); expGolomb += b; result = result * 2 + b; } result--; if (isItSigned) { result = (result + 1) / 2 * (result % 2 == 0 ? -1 : 1); } return result; } unsigned char* binaryData; int position; }; #endif 2012/1/10 Ross Finlayson <finlay...@live555.com>: > I check video stream width height from subsession > scs.subsession->videoHeight(), scs.subsession->videoHeight()... > > They give me right dimesions for server which desribe response include > "a=x-dimensions:%d,%d", &width, &height)"... > > But they give wrong value ( 0) for server which does NOT include > "a=x-dimensions:%d,%d", &width, &height)" > > > Exactly. The "MediaSubsession::videoHeight()" and > "MediaSubsession::videoWidth()" member functions (and other "MediaSession" > member functions) return the values that were obtained by parsing the > stream's SDP description. If, however, the corresponding fields are not in > the stream's SDP description, then 'null' values will be returned instead. > > > So i have to parse that subsession->fSpropParameterSets to get width.. > > > Yes. Just as you have to parse this, and all of the other NAL units if you > want to decode and play the H.264 video. > > > Is there a parser for fSpropParameterSets parameter s in Live555 > which i can extract video with height... > > > No. > > > Ross Finlayson > Live Networks, Inc. > http://www.live555.com/ > > > _______________________________________________ > live-devel mailing list > live-devel@lists.live555.com > http://lists.live555.com/mailman/listinfo/live-devel > _______________________________________________ live-devel mailing list live-devel@lists.live555.com http://lists.live555.com/mailman/listinfo/live-devel