Files
ANSCORE/MediaClient/media/media_parse.cpp

260 lines
7.0 KiB
C++
Raw Normal View History

2026-03-28 16:54:11 +11:00
/***************************************************************************************
*
* IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
*
* By downloading, copying, installing or using the software you agree to this license.
* If you do not agree to this license, do not download, install,
* copy or use the software.
*
* Copyright (C) 2014-2024, Happytimesoft Corporation, all rights reserved.
*
* Redistribution and use in binary forms, with or without modification, are permitted.
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*
****************************************************************************************/
#include "media_parse.h"
#include "media_format.h"
#include "media_util.h"
#include "h264.h"
#include "h265.h"
#include "mjpeg.h"
#include "h264_util.h"
#include "h265_util.h"
#include "bs.h"
#include <math.h>
int avc_parse_video_size(int codec, uint8 * p_data, uint32 len, int * width, int * height)
{
uint8 nalu_t;
if (p_data == NULL || len < 5)
{
return -1;
}
// Need to parse width X height
if (VIDEO_CODEC_H264 == codec)
{
int s_len = 0, n_len = 0, parse_len = len;
uint8 * p_cur = p_data;
uint8 * p_end = p_data + len;
while (p_cur && p_cur < p_end && parse_len > 0)
{
uint8 * p_next = avc_split_nalu(p_cur, parse_len, &s_len, &n_len);
nalu_t = (p_cur[s_len] & 0x1F);
int b_start;
nal_t nal;
nal.i_payload = n_len-s_len-1;
nal.p_payload = p_cur+s_len+1;
nal.i_type = nalu_t;
if (nalu_t == H264_NAL_SPS)
{
h264_t parse;
h264_parser_init(&parse);
h264_parser_parse(&parse, &nal, &b_start);
log_print(HT_LOG_INFO, "%s, H264 width[%d],height[%d]\r\n", __FUNCTION__, parse.i_width, parse.i_height);
*width = parse.i_width;
*height = parse.i_height;
return 0;
}
parse_len -= n_len;
p_cur = p_next;
}
}
else if (VIDEO_CODEC_H265 == codec)
{
int s_len, n_len = 0, parse_len = len;
uint8 * p_cur = p_data;
uint8 * p_end = p_data + len;
while (p_cur && p_cur < p_end && parse_len > 0)
{
uint8 * p_next = avc_split_nalu(p_cur, parse_len, &s_len, &n_len);
nalu_t = (p_cur[s_len] >> 1) & 0x3F;
if (nalu_t == HEVC_NAL_SPS)
{
h265_t parse;
h265_parser_init(&parse);
if (h265_parser_parse(&parse, p_cur+s_len, n_len-s_len) == 0)
{
log_print(HT_LOG_INFO, "%s, H265 width[%d],height[%d]\r\n", __FUNCTION__, parse.pic_width_in_luma_samples, parse.pic_height_in_luma_samples);
*width = parse.pic_width_in_luma_samples;
*height = parse.pic_height_in_luma_samples;
return 0;
}
}
parse_len -= n_len;
p_cur = p_next;
}
}
else if (VIDEO_CODEC_JPEG == codec)
{
uint32 offset = 0;
int size_chunk = 0;
while (offset < len - 8 && p_data[offset] == 0xFF)
{
if (p_data[offset+1] == MARKER_SOF0)
{
int h = ((p_data[offset+5] << 8) | p_data[offset+6]);
int w = ((p_data[offset+7] << 8) | p_data[offset+8]);
log_print(HT_LOG_INFO, "%s, MJPEG width[%d],height[%d]\r\n", __FUNCTION__, w, h);
*width = w;
*height = h;
break;
}
else if (p_data[offset+1] == MARKER_SOI)
{
offset += 2;
}
else
{
size_chunk = ((p_data[offset+2] << 8) | p_data[offset+3]);
offset += 2 + size_chunk;
}
}
}
else if (VIDEO_CODEC_MP4 == codec)
{
uint32 pos = 0;
int vol_f = 0;
int vol_pos = 0;
int vol_len = 0;
while (pos < len - 4)
{
if (p_data[pos] == 0 && p_data[pos+1] == 0 && p_data[pos+2] == 1)
{
if (p_data[pos+3] >= 0x20 && p_data[pos+3] <= 0x2F)
{
vol_f = 1;
vol_pos = pos+4;
}
else if (vol_f)
{
vol_len = pos - vol_pos;
break;
}
}
pos++;
}
if (!vol_f)
{
return 0;
}
else if (vol_len <= 0)
{
vol_len = len - vol_pos;
}
int vo_ver_id = 0;
bs_t bs;
bs_init(&bs, &p_data[vol_pos], vol_len * 8);
bs_skip(&bs, 1); /* random access */
bs_skip(&bs, 8); /* vo_type */
if (bs_read1(&bs)) /* is_ol_id */
{
vo_ver_id = bs_read(&bs, 4); /* vo_ver_id */
bs_skip(&bs, 3); /* vo_priority */
}
if (bs_read(&bs, 4) == 15) // aspect_ratio_info
{
bs_skip(&bs, 8); // par_width
bs_skip(&bs, 8); // par_height
}
if (bs_read1(&bs)) /* vol control parameter */
{
bs_read(&bs, 2);
bs_skip(&bs, 1); /* low_delay */
if (bs_read1(&bs))
{
/* vbv parameters */
bs_read(&bs, 15); /* first_half_bitrate */
bs_skip(&bs, 1);
bs_read(&bs, 15); /* latter_half_bitrate */
bs_skip(&bs, 1);
bs_read(&bs, 15); /* first_half_vbv_buffer_size */
bs_skip(&bs, 1);
bs_read(&bs, 3); /* latter_half_vbv_buffer_size */
bs_read(&bs, 11); /* first_half_vbv_occupancy */
bs_skip(&bs, 1);
bs_read(&bs, 15); /* latter_half_vbv_occupancy */
bs_skip(&bs, 1);
}
}
int shape = bs_read(&bs, 2); /* vol shape */
if (shape == 3 && vo_ver_id != 1)
{
bs_skip(&bs, 4); /* video_object_layer_shape_extension */
}
bs_skip(&bs, 1);
int framerate = bs_read(&bs, 16);
int time_increment_bits = (int) (log(framerate - 1.0) * 1.44269504088896340736 + 1); // log2(framerate - 1) + 1
if (time_increment_bits < 1)
{
time_increment_bits = 1;
}
bs_skip(&bs, 1);
if (bs_read1(&bs) != 0) /* fixed_vop_rate */
{
bs_skip(&bs, time_increment_bits);
}
if (shape != 2)
{
if (shape == 0)
{
bs_skip(&bs, 1);
int w = bs_read(&bs, 13);
bs_skip(&bs, 1);
int h = bs_read(&bs, 13);
log_print(HT_LOG_INFO, "%s, MPEG4 width[%d],height[%d]\r\n", __FUNCTION__, w, h);
*width = w;
*height = h;
return 0;
}
}
}
return -1;
}