Trang chủ‎ > ‎IT‎ > ‎Video Processing‎ > ‎

Parser for sprop-parameter-sets at desribe response to get width- height

Hi,

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)"... but INCLUDES
"sprop-parameter-sets......."...[ for h264 stream]...

So i have to parse that subsession->fSpropParameterSets to get width..
Is there a parser for  fSpropParameterSets parameter s in Live555
which i can extract video with height...

Best Wishes
Novalis
-------------------------------------------------------------------------------
> 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.
-------------------------------------------------------------------------------
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
-------------------------------------------------------------------------------------
> 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...

Note that we already provide a function:
	parseSPropParameterSets()
(defined in "liveMedia/include/H264VideoRTPSource.hh") that parses the "MediaSubsession::fmtp_spropparametersets()" string, Base64-decodes it, etc. - returning an array of NAL units (in binary form).

So you don't need to do the string-to-binary conversion.  Instead, you need focus on parsing the NAL unit binaries.
Comments