[Live-devel] Parser for sprop-parameter-sets at desribe response to get width- height...

Novalis Vapuru 6.45.vapuru at gmail.com
Mon Jan 9 23:57:09 PST 2012


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 <finlayson at 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 at lists.live555.com
> http://lists.live555.com/mailman/listinfo/live-devel
>



More information about the live-devel mailing list