[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