mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-11-10 08:38:20 +00:00
[client] added initial NAL unit parser
This commit is contained in:
parent
a36d312844
commit
50ba9b4899
@ -17,6 +17,7 @@ CFLAGS += -DBUILD_VERSION='"$(shell git describe --always --long --dirty --abbr
|
|||||||
OBJS = main.o \
|
OBJS = main.o \
|
||||||
lg-renderer.o \
|
lg-renderer.o \
|
||||||
spice/spice.o \
|
spice/spice.o \
|
||||||
|
parsers/nal.o \
|
||||||
decoders/null.o \
|
decoders/null.o \
|
||||||
decoders/h264.o \
|
decoders/h264.o \
|
||||||
renderers/opengl.o
|
renderers/opengl.o
|
||||||
|
@ -21,6 +21,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "memcpySSE.h"
|
#include "memcpySSE.h"
|
||||||
|
#include "parsers/nal.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -29,7 +30,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
|
|
||||||
#define SURFACE_NUM 3
|
#define SURFACE_NUM 3
|
||||||
|
|
||||||
#define NALU_AUD 9
|
|
||||||
#define SLICE_TYPE_P 0
|
#define SLICE_TYPE_P 0
|
||||||
#define SLICE_TYPE_B 1
|
#define SLICE_TYPE_B 1
|
||||||
#define SLICE_TYPE_I 2
|
#define SLICE_TYPE_I 2
|
||||||
@ -55,6 +55,8 @@ struct Inst
|
|||||||
VABufferID datBufferID[SURFACE_NUM];
|
VABufferID datBufferID[SURFACE_NUM];
|
||||||
bool t2First;
|
bool t2First;
|
||||||
int sliceType;
|
int sliceType;
|
||||||
|
|
||||||
|
NAL nal;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const unsigned char MatrixBufferH264[] = {
|
static const unsigned char MatrixBufferH264[] = {
|
||||||
@ -143,6 +145,13 @@ static bool lgd_h264_create(void ** opaque)
|
|||||||
this->sliBufferID[i] =
|
this->sliBufferID[i] =
|
||||||
this->datBufferID[i] = VA_INVALID_ID;
|
this->datBufferID[i] = VA_INVALID_ID;
|
||||||
|
|
||||||
|
if (!nal_initialize(&this->nal))
|
||||||
|
{
|
||||||
|
DEBUG_INFO("Failed to initialize NAL parser");
|
||||||
|
free(this);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
lgd_h264_deinitialize(this);
|
lgd_h264_deinitialize(this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -450,13 +459,22 @@ static bool setup_pic_buffer(struct Inst * this)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const NAL_SPS * sps;
|
||||||
|
if (!nal_get_sps(this->nal, &sps))
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("nal_get_sps");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
memset(p, 0, sizeof(VAPictureParameterBufferH264));
|
memset(p, 0, sizeof(VAPictureParameterBufferH264));
|
||||||
p->picture_width_in_mbs_minus1 = (this->format.width + 15) / 16;
|
p->picture_width_in_mbs_minus1 = sps->pic_width_in_mbs_minus1;
|
||||||
p->picture_width_in_mbs_minus1 = (this->format.height + 15) / 16;
|
p->picture_height_in_mbs_minus1 = sps->pic_height_in_map_units_minus1;
|
||||||
p->num_ref_frames = 1;
|
p->bit_depth_luma_minus8 = sps->bit_depth_luma_minus8;
|
||||||
p->seq_fields.value = 145;
|
p->bit_depth_chroma_minus8 = sps->bit_depth_chroma_minus8;
|
||||||
p->pic_fields.value = 0x501;
|
p->num_ref_frames = sps->num_ref_frames;
|
||||||
p->frame_num = this->frameNum % 16;
|
p->seq_fields.value = 145;
|
||||||
|
p->pic_fields.value = 0x501;
|
||||||
|
p->frame_num = this->frameNum % 16;
|
||||||
for(int i = 0; i < 16; ++i)
|
for(int i = 0; i < 16; ++i)
|
||||||
{
|
{
|
||||||
p->ReferenceFrames[i].flags = VA_PICTURE_H264_INVALID;
|
p->ReferenceFrames[i].flags = VA_PICTURE_H264_INVALID;
|
||||||
@ -592,55 +610,33 @@ static bool setup_dat_buffer(struct Inst * this, const uint8_t * src, size_t src
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool parse_nalu(struct Inst * this, const uint8_t * src, size_t size)
|
|
||||||
{
|
|
||||||
static const uint8_t startCode[4] = {0x00, 0x00, 0x00, 0x01};
|
|
||||||
|
|
||||||
if (memcmp(src, startCode, sizeof(startCode)) != 0)
|
|
||||||
{
|
|
||||||
DEBUG_ERROR("Missing start code");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
src += 4;
|
|
||||||
|
|
||||||
if (*src & 0x80)
|
|
||||||
{
|
|
||||||
DEBUG_ERROR("forbidden_zero_bit is set");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// uint8_t nal_ref_idc = (*src & 0x60) >> 5;
|
|
||||||
uint8_t nal_ref_unit_type = (*src & 0x1F);
|
|
||||||
++src;
|
|
||||||
|
|
||||||
if (nal_ref_unit_type == NALU_AUD)
|
|
||||||
{
|
|
||||||
static const int pic_type_to_slice_type[3] =
|
|
||||||
{
|
|
||||||
SLICE_TYPE_I,
|
|
||||||
SLICE_TYPE_P,
|
|
||||||
SLICE_TYPE_B
|
|
||||||
};
|
|
||||||
|
|
||||||
const uint8_t primary_pic_type = (*src & 0xE0) >> 5;
|
|
||||||
this->sliceType = pic_type_to_slice_type[primary_pic_type];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool lgd_h264_decode(void * opaque, const uint8_t * src, size_t srcSize)
|
static bool lgd_h264_decode(void * opaque, const uint8_t * src, size_t srcSize)
|
||||||
{
|
{
|
||||||
VAStatus status;
|
VAStatus status;
|
||||||
struct Inst * this = (struct Inst *)opaque;
|
struct Inst * this = (struct Inst *)opaque;
|
||||||
|
|
||||||
if (!parse_nalu(this, src, srcSize))
|
if (!nal_parse(this->nal, src, srcSize))
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("Failed to parse required information");
|
DEBUG_ERROR("Failed to parse required information");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t pic_type;
|
||||||
|
if (!nal_get_primary_picture_type(this->nal, &pic_type))
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("Missing primary picture type");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const int pic_type_to_slice_type[3] =
|
||||||
|
{
|
||||||
|
SLICE_TYPE_I,
|
||||||
|
SLICE_TYPE_P,
|
||||||
|
SLICE_TYPE_B
|
||||||
|
};
|
||||||
|
|
||||||
|
this->sliceType = pic_type_to_slice_type[pic_type];
|
||||||
|
|
||||||
// don't start until we have an I-FRAME
|
// don't start until we have an I-FRAME
|
||||||
if (this->frameNum == 0 && this->sliceType != SLICE_TYPE_I)
|
if (this->frameNum == 0 && this->sliceType != SLICE_TYPE_I)
|
||||||
return true;
|
return true;
|
||||||
|
453
client/parsers/nal.c
Normal file
453
client/parsers/nal.c
Normal file
@ -0,0 +1,453 @@
|
|||||||
|
/*
|
||||||
|
Looking Glass - KVM FrameRelay (KVMFR) Client
|
||||||
|
Copyright (C) 2017 Geoffrey McRae <geoff@hostfission.com>
|
||||||
|
https://looking-glass.hostfission.com
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
|
Foundation; either version 2 of the License, or (at your option) any later
|
||||||
|
version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||||
|
Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "nal.h"
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define DEBUG_NAL
|
||||||
|
|
||||||
|
struct NAL
|
||||||
|
{
|
||||||
|
uint8_t primary_pic_type;
|
||||||
|
bool primary_pic_type_valid;
|
||||||
|
|
||||||
|
bool sps_valid;
|
||||||
|
NAL_SPS sps;
|
||||||
|
int32_t * sps_offset_for_ref_frame;
|
||||||
|
uint32_t sps_num_ref_frames_in_pic_order_cnt_cycle;
|
||||||
|
|
||||||
|
NAL_VUI vui;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool nal_initialize(NAL * ptr)
|
||||||
|
{
|
||||||
|
*ptr = (NAL)malloc(sizeof(struct NAL));
|
||||||
|
memset(*ptr, 0, sizeof(struct NAL));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nal_deinitialize(NAL this)
|
||||||
|
{
|
||||||
|
if (this->sps_offset_for_ref_frame)
|
||||||
|
{
|
||||||
|
free(this->sps_offset_for_ref_frame);
|
||||||
|
this->sps_offset_for_ref_frame = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->vui.nal_hrd_parameters.cpb)
|
||||||
|
{
|
||||||
|
free(this->vui.nal_hrd_parameters.cpb);
|
||||||
|
this->vui.nal_hrd_parameters.cpb = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->vui.vcl_hrd_parameters.cpb)
|
||||||
|
{
|
||||||
|
free(this->vui.vcl_hrd_parameters.cpb);
|
||||||
|
this->vui.vcl_hrd_parameters.cpb = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parse_nal_hrd(NAL_HRD * const hrd, const uint8_t * src, size_t size, size_t * const offset)
|
||||||
|
{
|
||||||
|
hrd->cpb_cnt_minus1 = decode_u_golomb(src, offset);
|
||||||
|
hrd->bit_rate_scale = get_bits(src, offset, 4);
|
||||||
|
hrd->cpb_size_scale = get_bits(src, offset, 4);
|
||||||
|
|
||||||
|
if (hrd->cpb_size_count < hrd->cpb_size_scale)
|
||||||
|
{
|
||||||
|
hrd->cpb = realloc(hrd->cpb, hrd->cpb_size_scale * sizeof(NAL_CPB));
|
||||||
|
hrd->cpb_size_count = hrd->cpb_size_scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(uint32_t i = 0; i < hrd->cpb_size_scale; ++i)
|
||||||
|
{
|
||||||
|
hrd->cpb[i].bit_rate_value_minus1 = decode_u_golomb(src, offset);
|
||||||
|
hrd->cpb[i].cpb_size_value_minus1 = decode_u_golomb(src, offset);
|
||||||
|
hrd->cpb[i].cbr_flag = get_bit(src, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
hrd->initial_cpb_removal_delay_length_minus1 = get_bits(src, offset, 5);
|
||||||
|
hrd->cpb_removal_delay_length_minus1 = get_bits(src, offset, 5);
|
||||||
|
hrd->dpb_output_delay_length_minus1 = get_bits(src, offset, 5);
|
||||||
|
hrd->time_offset_length = get_bits(src, offset, 5);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parse_nal_vui(NAL_VUI * const vui, const uint8_t * src, size_t size, size_t * const offset)
|
||||||
|
{
|
||||||
|
NAL_CPB * nal_hrd_cpb = vui->nal_hrd_parameters.cpb;
|
||||||
|
uint8_t nal_hrd_count = vui->nal_hrd_parameters.cpb_size_count;
|
||||||
|
NAL_CPB * vcl_hrd_cpb = vui->vcl_hrd_parameters.cpb;
|
||||||
|
uint8_t vcl_hrd_count = vui->vcl_hrd_parameters.cpb_size_count;
|
||||||
|
memset(vui, 0, sizeof(NAL_VUI));
|
||||||
|
vui->nal_hrd_parameters.cpb = nal_hrd_cpb;
|
||||||
|
vui->nal_hrd_parameters.cpb_size_count = nal_hrd_count;
|
||||||
|
vui->vcl_hrd_parameters.cpb = vcl_hrd_cpb;
|
||||||
|
vui->vcl_hrd_parameters.cpb_size_count = vcl_hrd_count;
|
||||||
|
|
||||||
|
vui->aspect_ratio_info_present_flag = get_bit(src, offset);
|
||||||
|
if (vui->aspect_ratio_info_present_flag)
|
||||||
|
{
|
||||||
|
vui->aspect_ratio_idc = get_bits(src, offset, 8);
|
||||||
|
if (vui->aspect_ratio_idc == IDC_VUI_ASPECT_RATIO_EXTENDED_SAR)
|
||||||
|
{
|
||||||
|
vui->sar_width = get_bits(src, offset, 16);
|
||||||
|
vui->sar_height = get_bits(src, offset, 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vui->overscan_info_present_flag = get_bit(src, offset);
|
||||||
|
if (vui->overscan_info_present_flag)
|
||||||
|
vui->overscan_appropriate_flag = get_bit(src, offset);
|
||||||
|
|
||||||
|
vui->video_signal_type_present_flag = get_bit(src, offset);
|
||||||
|
if (vui->video_signal_type_present_flag)
|
||||||
|
{
|
||||||
|
vui->video_format = get_bits(src, offset, 3);
|
||||||
|
vui->video_full_range_flag = get_bit(src, offset);
|
||||||
|
vui->colour_description_present_flag = get_bit(src, offset);
|
||||||
|
if (vui->colour_description_present_flag)
|
||||||
|
{
|
||||||
|
vui->colour_primaries = get_bits(src, offset, 8);
|
||||||
|
vui->transfer_characteristics = get_bits(src, offset, 8);
|
||||||
|
vui->matrix_coefficients = get_bits(src, offset, 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vui->chroma_loc_info_present_flag = get_bit(src, offset);
|
||||||
|
if (vui->chroma_loc_info_present_flag)
|
||||||
|
{
|
||||||
|
vui->chroma_sample_loc_type_top_field = decode_u_golomb(src, offset);
|
||||||
|
vui->chroma_sample_loc_type_bottom_field = decode_u_golomb(src, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
vui->timing_info_present_flag = get_bit(src, offset);
|
||||||
|
if (vui->timing_info_present_flag)
|
||||||
|
{
|
||||||
|
vui->num_units_in_tick = get_bits(src, offset, 32);
|
||||||
|
vui->time_scale = get_bits(src, offset, 32);
|
||||||
|
vui->fixed_frame_rate_flag = get_bit(src, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
vui->nal_hrd_parameters_present_flag = get_bit(src, offset);
|
||||||
|
if (vui->nal_hrd_parameters_present_flag)
|
||||||
|
if (!parse_nal_hrd(&vui->nal_hrd_parameters, src, size, offset))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
vui->vcl_hrd_parameters_present_flag = get_bit(src, offset);
|
||||||
|
if (vui->vcl_hrd_parameters_present_flag)
|
||||||
|
if (!parse_nal_hrd(&vui->vcl_hrd_parameters, src, size, offset))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (vui->nal_hrd_parameters_present_flag || vui->vcl_hrd_parameters_present_flag)
|
||||||
|
vui->low_delay_hrd_flag = get_bit(src, offset);
|
||||||
|
|
||||||
|
vui->pic_struct_present_flag = get_bit(src, offset);
|
||||||
|
vui->bitstream_restriction_flag = get_bit(src, offset);
|
||||||
|
if (vui->bitstream_restriction_flag)
|
||||||
|
{
|
||||||
|
vui->motion_vectors_over_pic_boundaries_flag = get_bit(src, offset);
|
||||||
|
vui->max_bytes_per_pic_denom = decode_u_golomb(src, offset);
|
||||||
|
vui->max_bits_per_mb_denom = decode_u_golomb(src, offset);
|
||||||
|
vui->log2_max_mv_length_horizontal = decode_u_golomb(src, offset);
|
||||||
|
vui->log2_max_mv_length_vertical = decode_u_golomb(src, offset);
|
||||||
|
vui->num_reorder_frames = decode_u_golomb(src, offset);
|
||||||
|
vui->max_dec_frame_buffering = decode_u_golomb(src, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parse_nal_trailing_bits(NAL this, const uint8_t * src, size_t size, size_t * const offset)
|
||||||
|
{
|
||||||
|
if (!get_bit(src, offset))
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("Missing stop bit");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// byte align
|
||||||
|
*offset = (*offset + 0x7) & ~0x7;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parse_nal_sps(NAL this, const uint8_t * src, size_t size, size_t * const offset)
|
||||||
|
{
|
||||||
|
this->sps_valid = false;
|
||||||
|
memset(&this->sps, 0, sizeof(this->sps));
|
||||||
|
|
||||||
|
this->sps.profile_idc = get_bits(src, offset, 8);
|
||||||
|
if ((this->sps.profile_idc != IDC_PROFILE_BASELINE) &&
|
||||||
|
(this->sps.profile_idc != IDC_PROFILE_MAIN ) &&
|
||||||
|
(this->sps.profile_idc != IDC_PROFILE_EXTENDED) &&
|
||||||
|
(this->sps.profile_idc != IDC_PROFILE_HP ) &&
|
||||||
|
(this->sps.profile_idc != IDC_PROFILE_Hi10P ) &&
|
||||||
|
(this->sps.profile_idc != IDC_PROFILE_Hi422 ) &&
|
||||||
|
(this->sps.profile_idc != IDC_PROFILE_Hi444 ) &&
|
||||||
|
(this->sps.profile_idc != IDC_PROFILE_CAVLC444))
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("Invalid profile IDC (%d) encountered", this->sps.profile_idc);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->sps.constraint_set_flags[0] = get_bit(src, offset);
|
||||||
|
this->sps.constraint_set_flags[1] = get_bit(src, offset);
|
||||||
|
this->sps.constraint_set_flags[2] = get_bit(src, offset);
|
||||||
|
*offset += 5;
|
||||||
|
|
||||||
|
this->sps.level_idc = get_bits(src, offset, 8);
|
||||||
|
this->sps.seq_parameter_set_id = decode_u_golomb(src, offset);
|
||||||
|
|
||||||
|
if ((this->sps.profile_idc == IDC_PROFILE_HP ) ||
|
||||||
|
(this->sps.profile_idc == IDC_PROFILE_Hi10P ) ||
|
||||||
|
(this->sps.profile_idc == IDC_PROFILE_Hi422 ) ||
|
||||||
|
(this->sps.profile_idc == IDC_PROFILE_Hi444 ) ||
|
||||||
|
(this->sps.profile_idc == IDC_PROFILE_CAVLC444))
|
||||||
|
{
|
||||||
|
this->sps.chroma_format_idc = decode_u_golomb(src, offset);
|
||||||
|
if (this->sps.chroma_format_idc == IDC_CHROMA_FORMAT_YUV444)
|
||||||
|
this->sps.seperate_colour_plane_flag = get_bit(src, offset);
|
||||||
|
|
||||||
|
this->sps.bit_depth_luma_minus8 = decode_u_golomb(src, offset);
|
||||||
|
this->sps.bit_depth_chroma_minus8 = decode_u_golomb(src, offset);
|
||||||
|
this->sps.lossless_qpprime_y_zero_flag = get_bit(src, offset);
|
||||||
|
this->sps.seq_scaling_matrix_present_flag = get_bit(src, offset);
|
||||||
|
|
||||||
|
if (this->sps.seq_scaling_matrix_present_flag)
|
||||||
|
{
|
||||||
|
const int cnt = this->sps.chroma_format_idc == IDC_CHROMA_FORMAT_YUV444 ? 12 : 8;
|
||||||
|
for(int i = 0; i < cnt; ++i)
|
||||||
|
this->sps.seq_scaling_list_present_flag[i] = get_bit(src, offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
this->sps.chroma_format_idc = IDC_CHROMA_FORMAT_YUV420;
|
||||||
|
|
||||||
|
this->sps.log2_max_frame_num_minus4 = decode_u_golomb(src, offset);
|
||||||
|
this->sps.pic_order_cnt_type = decode_u_golomb(src, offset);
|
||||||
|
|
||||||
|
if (this->sps.pic_order_cnt_type == 0)
|
||||||
|
this->sps.log2_max_pic_order_cnt_lsb_minus4 = decode_u_golomb(src, offset);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (this->sps.pic_order_cnt_type == 1)
|
||||||
|
{
|
||||||
|
this->sps.delta_pic_order_always_zero_flag = get_bit(src, offset);
|
||||||
|
this->sps.offset_for_non_ref_pic = decode_s_golomb(src, offset);
|
||||||
|
this->sps.offset_for_top_to_bottom_field = decode_s_golomb(src, offset);
|
||||||
|
|
||||||
|
this->sps.num_ref_frames_in_pic_order_cnt_cycle = decode_u_golomb(src, offset);
|
||||||
|
if (this->sps.num_ref_frames_in_pic_order_cnt_cycle > this->sps_num_ref_frames_in_pic_order_cnt_cycle)
|
||||||
|
{
|
||||||
|
this->sps_offset_for_ref_frame = realloc(
|
||||||
|
this->sps_offset_for_ref_frame,
|
||||||
|
this->sps.num_ref_frames_in_pic_order_cnt_cycle * sizeof(int32_t)
|
||||||
|
);
|
||||||
|
this->sps_num_ref_frames_in_pic_order_cnt_cycle = this->sps.num_ref_frames_in_pic_order_cnt_cycle;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->sps.offset_for_ref_frame = this->sps_offset_for_ref_frame;
|
||||||
|
for(uint32_t i = 0; i < this->sps.num_ref_frames_in_pic_order_cnt_cycle; ++i)
|
||||||
|
this->sps.offset_for_ref_frame[i] = decode_s_golomb(src, offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this->sps.num_ref_frames = decode_u_golomb(src, offset);
|
||||||
|
this->sps.gaps_in_frame_num_value_allowed_flag = get_bit(src, offset);
|
||||||
|
this->sps.pic_width_in_mbs_minus1 = decode_u_golomb(src, offset);
|
||||||
|
this->sps.pic_height_in_map_units_minus1 = decode_u_golomb(src, offset);
|
||||||
|
this->sps.frame_mbs_only_flag = get_bit(src, offset);
|
||||||
|
|
||||||
|
if (!this->sps.frame_mbs_only_flag)
|
||||||
|
this->sps.mb_adaptive_frame_field_flag = get_bit(src, offset);
|
||||||
|
|
||||||
|
this->sps.direct_8x8_inference_flag = get_bit(src, offset);
|
||||||
|
this->sps.frame_cropping_flag = get_bit(src, offset);
|
||||||
|
|
||||||
|
if (this->sps.frame_cropping_flag)
|
||||||
|
{
|
||||||
|
this->sps.frame_crop_left_offset = decode_u_golomb(src, offset);
|
||||||
|
this->sps.frame_crop_right_offset = decode_u_golomb(src, offset);
|
||||||
|
this->sps.frame_crop_top_offset = decode_u_golomb(src, offset);
|
||||||
|
this->sps.frame_crop_bottom_offset = decode_u_golomb(src, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->sps.vui_parameters_present_flag = get_bit(src, offset);
|
||||||
|
|
||||||
|
#ifdef DEBUG_NAL
|
||||||
|
DEBUG_INFO("SPS\n"
|
||||||
|
"profile_idc : %u\n"
|
||||||
|
"constraint_set_flags : %u %u %u\n"
|
||||||
|
"level_idc : %u\n"
|
||||||
|
"sec_parameter_set_id : %u\n"
|
||||||
|
"chroma_format_idc : %u\n"
|
||||||
|
"seperate_colour_plane_flag : %u\n"
|
||||||
|
"bit_depth_luma_minus8 : %u\n"
|
||||||
|
"bit_depth_chroma_minus8 : %u\n"
|
||||||
|
"lossless_qpprime_y_zero_flag : %u\n"
|
||||||
|
"seq_scaling_matrix_present_flag : %u\n"
|
||||||
|
"log2_max_frame_num_minus4 : %u\n"
|
||||||
|
"pic_order_cnt_type : %u\n"
|
||||||
|
"log2_max_pic_order_cnt_lsb_minus4 : %u\n"
|
||||||
|
"delta_pic_order_always_zero_flag : %u\n"
|
||||||
|
"offset_for_non_ref_pic : %d\n"
|
||||||
|
"offset_for_top_to_bottom_field : %d\n"
|
||||||
|
"num_ref_frames_in_pic_order_cnt_cycle: %u\n"
|
||||||
|
"num_ref_frames : %u\n"
|
||||||
|
"gaps_in_frame_num_value_allowed_flag : %u\n"
|
||||||
|
"pic_width_in_mbs_minus1 : %3u (%u)\n"
|
||||||
|
"pic_height_in_map_units_minus1 : %3u (%u)\n"
|
||||||
|
"frame_mbs_only_flag : %u\n"
|
||||||
|
"mb_adaptive_frame_field_flag : %u\n"
|
||||||
|
"direct_8x8_inference_flag : %u\n"
|
||||||
|
"frame_cropping_flag : %u\n"
|
||||||
|
"frame_crop_left_offset : %u\n"
|
||||||
|
"frame_crop_right_offset : %u\n"
|
||||||
|
"frame_crop_top_offset : %u\n"
|
||||||
|
"frame_crop_bottom_offset : %u\n"
|
||||||
|
"vui_parameters_present_flag : %u",
|
||||||
|
this->sps.profile_idc,
|
||||||
|
this->sps.constraint_set_flags[0],
|
||||||
|
this->sps.constraint_set_flags[1],
|
||||||
|
this->sps.constraint_set_flags[2],
|
||||||
|
this->sps.level_idc,
|
||||||
|
this->sps.seq_parameter_set_id,
|
||||||
|
this->sps.chroma_format_idc,
|
||||||
|
this->sps.seperate_colour_plane_flag,
|
||||||
|
this->sps.bit_depth_luma_minus8,
|
||||||
|
this->sps.bit_depth_chroma_minus8,
|
||||||
|
this->sps.lossless_qpprime_y_zero_flag,
|
||||||
|
this->sps.seq_scaling_matrix_present_flag,
|
||||||
|
this->sps.log2_max_frame_num_minus4,
|
||||||
|
this->sps.pic_order_cnt_type,
|
||||||
|
this->sps.log2_max_pic_order_cnt_lsb_minus4,
|
||||||
|
this->sps.delta_pic_order_always_zero_flag,
|
||||||
|
this->sps.offset_for_non_ref_pic,
|
||||||
|
this->sps.offset_for_top_to_bottom_field,
|
||||||
|
this->sps.num_ref_frames_in_pic_order_cnt_cycle,
|
||||||
|
this->sps.num_ref_frames,
|
||||||
|
this->sps.gaps_in_frame_num_value_allowed_flag,
|
||||||
|
this->sps.pic_width_in_mbs_minus1 , (this->sps.pic_width_in_mbs_minus1 + 1) * 16,
|
||||||
|
this->sps.pic_height_in_map_units_minus1, (this->sps.pic_height_in_map_units_minus1 + 1) * 16,
|
||||||
|
this->sps.frame_mbs_only_flag,
|
||||||
|
this->sps.mb_adaptive_frame_field_flag,
|
||||||
|
this->sps.direct_8x8_inference_flag,
|
||||||
|
this->sps.frame_cropping_flag,
|
||||||
|
this->sps.frame_crop_left_offset,
|
||||||
|
this->sps.frame_crop_right_offset,
|
||||||
|
this->sps.frame_crop_top_offset,
|
||||||
|
this->sps.frame_crop_bottom_offset,
|
||||||
|
this->sps.vui_parameters_present_flag
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (this->sps.vui_parameters_present_flag)
|
||||||
|
if (!parse_nal_vui(&this->vui, src, size, offset))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!parse_nal_trailing_bits(this, src, size, offset))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
this->sps_valid = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nal_parse(NAL this, const uint8_t * src, size_t size)
|
||||||
|
{
|
||||||
|
static FILE * fd = NULL;
|
||||||
|
if (!fd)
|
||||||
|
fd = fopen("/tmp/stream.h264", "w");
|
||||||
|
fwrite(src, size, 1, fd);
|
||||||
|
|
||||||
|
const size_t bits = size << 4;
|
||||||
|
size_t offset = 0;
|
||||||
|
while(offset < bits)
|
||||||
|
{
|
||||||
|
// look for the start header
|
||||||
|
if (get_bits(src, &offset, 32) != 1)
|
||||||
|
{
|
||||||
|
offset -= 24;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure the forbidden zero bit is not set
|
||||||
|
if (get_bit(src, &offset) != 0)
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("forbidden_zero_bit is set");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t nal_ref_idc = get_bits(src, &offset, 2);
|
||||||
|
uint8_t nal_ref_unit_type = get_bits(src, &offset, 5);
|
||||||
|
DEBUG_INFO("ref idc: %d, ref unit type: %d", nal_ref_idc, nal_ref_unit_type);
|
||||||
|
|
||||||
|
switch(nal_ref_unit_type)
|
||||||
|
{
|
||||||
|
case NAL_TYPE_AUD:
|
||||||
|
{
|
||||||
|
this->primary_pic_type = get_bits(src, &offset, 3);
|
||||||
|
this->primary_pic_type_valid = true;
|
||||||
|
if (!parse_nal_trailing_bits(this, src, size, &offset))
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case NAL_TYPE_SPS:
|
||||||
|
if (!parse_nal_sps(this, src, size, &offset))
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NAL_TYPE_PPS:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
DEBUG_ERROR("Unknown NAL ref unit type: %d", nal_ref_unit_type);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// byte align
|
||||||
|
offset = (offset + 0x7) & ~0x7;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nal_get_sps(NAL this, const NAL_SPS ** sps)
|
||||||
|
{
|
||||||
|
if (!this->sps_valid)
|
||||||
|
return false;
|
||||||
|
*sps = &this->sps;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nal_get_primary_picture_type(NAL this, uint8_t * pic_type)
|
||||||
|
{
|
||||||
|
if (!this->primary_pic_type_valid)
|
||||||
|
return false;
|
||||||
|
*pic_type = this->primary_pic_type;
|
||||||
|
return true;
|
||||||
|
}
|
153
client/parsers/nal.h
Normal file
153
client/parsers/nal.h
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
/*
|
||||||
|
Looking Glass - KVM FrameRelay (KVMFR) Client
|
||||||
|
Copyright (C) 2017 Geoffrey McRae <geoff@hostfission.com>
|
||||||
|
https://looking-glass.hostfission.com
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
|
Foundation; either version 2 of the License, or (at your option) any later
|
||||||
|
version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||||
|
Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define NAL_TYPE_SPS 7
|
||||||
|
#define NAL_TYPE_PPS 8
|
||||||
|
#define NAL_TYPE_AUD 9
|
||||||
|
|
||||||
|
#define IDC_PROFILE_BASELINE 66
|
||||||
|
#define IDC_PROFILE_MAIN 77
|
||||||
|
#define IDC_PROFILE_EXTENDED 88
|
||||||
|
#define IDC_PROFILE_HP 100
|
||||||
|
#define IDC_PROFILE_Hi10P 110
|
||||||
|
#define IDC_PROFILE_Hi422 122
|
||||||
|
#define IDC_PROFILE_Hi444 244
|
||||||
|
#define IDC_PROFILE_CAVLC444 44
|
||||||
|
|
||||||
|
#define IDC_CHROMA_FORMAT_YUV400 0
|
||||||
|
#define IDC_CHROMA_FORMAT_YUV420 1
|
||||||
|
#define IDC_CHROMA_FORMAT_YVU422 2
|
||||||
|
#define IDC_CHROMA_FORMAT_YUV444 3
|
||||||
|
|
||||||
|
#define IDC_VUI_ASPECT_RATIO_EXTENDED_SAR 0xFF
|
||||||
|
|
||||||
|
#define NAL_PICTURE_TYPE_I 0
|
||||||
|
#define NAL_PICTURE_TYPE_P 1
|
||||||
|
#define NAL_PICTURE_TYPE_B 2
|
||||||
|
|
||||||
|
typedef struct NAL_SPS
|
||||||
|
{
|
||||||
|
uint8_t profile_idc;
|
||||||
|
uint8_t constraint_set_flags[3];
|
||||||
|
uint8_t level_idc;
|
||||||
|
uint32_t seq_parameter_set_id;
|
||||||
|
uint32_t chroma_format_idc;
|
||||||
|
uint8_t seperate_colour_plane_flag;
|
||||||
|
uint32_t bit_depth_luma_minus8;
|
||||||
|
uint32_t bit_depth_chroma_minus8;
|
||||||
|
uint8_t lossless_qpprime_y_zero_flag;
|
||||||
|
uint8_t seq_scaling_matrix_present_flag;
|
||||||
|
uint8_t seq_scaling_list_present_flag[12];
|
||||||
|
uint32_t log2_max_frame_num_minus4;
|
||||||
|
uint32_t pic_order_cnt_type;
|
||||||
|
uint32_t log2_max_pic_order_cnt_lsb_minus4;
|
||||||
|
uint8_t delta_pic_order_always_zero_flag;
|
||||||
|
int32_t offset_for_non_ref_pic;
|
||||||
|
int32_t offset_for_top_to_bottom_field;
|
||||||
|
uint32_t num_ref_frames_in_pic_order_cnt_cycle;
|
||||||
|
int32_t * offset_for_ref_frame;
|
||||||
|
uint32_t num_ref_frames;
|
||||||
|
uint8_t gaps_in_frame_num_value_allowed_flag;
|
||||||
|
uint32_t pic_width_in_mbs_minus1;
|
||||||
|
uint32_t pic_height_in_map_units_minus1;
|
||||||
|
uint8_t frame_mbs_only_flag;
|
||||||
|
uint8_t mb_adaptive_frame_field_flag;
|
||||||
|
uint8_t direct_8x8_inference_flag;
|
||||||
|
uint8_t frame_cropping_flag;
|
||||||
|
uint32_t frame_crop_left_offset;
|
||||||
|
uint32_t frame_crop_right_offset;
|
||||||
|
uint32_t frame_crop_top_offset;
|
||||||
|
uint32_t frame_crop_bottom_offset;
|
||||||
|
uint8_t vui_parameters_present_flag;
|
||||||
|
}
|
||||||
|
NAL_SPS;
|
||||||
|
|
||||||
|
typedef struct NAL_CPB
|
||||||
|
{
|
||||||
|
uint32_t bit_rate_value_minus1;
|
||||||
|
uint32_t cpb_size_value_minus1;
|
||||||
|
uint8_t cbr_flag;
|
||||||
|
}
|
||||||
|
NAL_CPB;
|
||||||
|
|
||||||
|
typedef struct NAL_HRD
|
||||||
|
{
|
||||||
|
uint32_t cpb_cnt_minus1;
|
||||||
|
uint8_t bit_rate_scale;
|
||||||
|
uint8_t cpb_size_scale;
|
||||||
|
uint8_t cpb_size_count;
|
||||||
|
NAL_CPB * cpb;
|
||||||
|
uint8_t initial_cpb_removal_delay_length_minus1;
|
||||||
|
uint8_t cpb_removal_delay_length_minus1;
|
||||||
|
uint8_t dpb_output_delay_length_minus1;
|
||||||
|
uint8_t time_offset_length;
|
||||||
|
}
|
||||||
|
NAL_HRD;
|
||||||
|
|
||||||
|
typedef struct NAL_VUI
|
||||||
|
{
|
||||||
|
uint8_t aspect_ratio_info_present_flag;
|
||||||
|
uint8_t aspect_ratio_idc;
|
||||||
|
uint16_t sar_width;
|
||||||
|
uint16_t sar_height;
|
||||||
|
uint8_t overscan_info_present_flag;
|
||||||
|
uint8_t overscan_appropriate_flag;
|
||||||
|
uint8_t video_signal_type_present_flag;
|
||||||
|
uint8_t video_format;
|
||||||
|
uint8_t video_full_range_flag;
|
||||||
|
uint8_t colour_description_present_flag;
|
||||||
|
uint8_t colour_primaries;
|
||||||
|
uint8_t transfer_characteristics;
|
||||||
|
uint8_t matrix_coefficients;
|
||||||
|
uint8_t chroma_loc_info_present_flag;
|
||||||
|
uint32_t chroma_sample_loc_type_top_field;
|
||||||
|
uint32_t chroma_sample_loc_type_bottom_field;
|
||||||
|
uint8_t timing_info_present_flag;
|
||||||
|
uint32_t num_units_in_tick;
|
||||||
|
uint32_t time_scale;
|
||||||
|
uint8_t fixed_frame_rate_flag;
|
||||||
|
uint8_t nal_hrd_parameters_present_flag;
|
||||||
|
NAL_HRD nal_hrd_parameters;
|
||||||
|
uint8_t vcl_hrd_parameters_present_flag;
|
||||||
|
NAL_HRD vcl_hrd_parameters;
|
||||||
|
uint8_t low_delay_hrd_flag;
|
||||||
|
uint8_t pic_struct_present_flag;
|
||||||
|
uint8_t bitstream_restriction_flag;
|
||||||
|
uint8_t motion_vectors_over_pic_boundaries_flag;
|
||||||
|
uint32_t max_bytes_per_pic_denom;
|
||||||
|
uint32_t max_bits_per_mb_denom;
|
||||||
|
uint32_t log2_max_mv_length_horizontal;
|
||||||
|
uint32_t log2_max_mv_length_vertical;
|
||||||
|
uint32_t num_reorder_frames;
|
||||||
|
uint32_t max_dec_frame_buffering;
|
||||||
|
}
|
||||||
|
NAL_VUI;
|
||||||
|
|
||||||
|
typedef struct NAL * NAL;
|
||||||
|
|
||||||
|
bool nal_initialize (NAL * ptr);
|
||||||
|
void nal_deinitialize(NAL this );
|
||||||
|
bool nal_parse (NAL this, const uint8_t * src, size_t size);
|
||||||
|
|
||||||
|
bool nal_get_sps (NAL this, const NAL_SPS ** sps);
|
||||||
|
bool nal_get_primary_picture_type(NAL this, uint8_t * pic_type);
|
@ -61,3 +61,33 @@ static inline void nsleep(uint64_t ns)
|
|||||||
#define LG_UNLOCK(x) SDL_UnlockMutex(x)
|
#define LG_UNLOCK(x) SDL_UnlockMutex(x)
|
||||||
#define LG_LOCK_FREE(x) SDL_DestroyMutex(x)
|
#define LG_LOCK_FREE(x) SDL_DestroyMutex(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static inline uint32_t get_bit(const uint8_t * const base, size_t * const offset)
|
||||||
|
{
|
||||||
|
uint32_t out = ((*(base + (*offset >> 0x3))) >> (0x7 - (*offset & 0x7))) & 0x1;
|
||||||
|
++*offset;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t get_bits(const uint8_t * const base, size_t * const offset, const uint8_t bits)
|
||||||
|
{
|
||||||
|
uint32_t value = 0;
|
||||||
|
for (int i = 0; i < bits; ++i)
|
||||||
|
value |= (get_bit(base, offset) ? 1 : 0) << (bits - i - 1);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t decode_u_golomb(const uint8_t * const base, size_t * const offset)
|
||||||
|
{
|
||||||
|
uint32_t i = 0;
|
||||||
|
while(get_bit(base, offset) == 0)
|
||||||
|
++i;
|
||||||
|
|
||||||
|
return ((1 << i) - 1 + get_bits(base, offset, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int32_t decode_s_golomb(const uint8_t * const base, size_t * const offset)
|
||||||
|
{
|
||||||
|
const uint32_t g = decode_u_golomb(base, offset);
|
||||||
|
return (g & 0x1) ? (g + 1) / 2 : -(g / 2);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user