260 lines
7.0 KiB
C++
260 lines
7.0 KiB
C++
/***************************************************************************************
|
|
*
|
|
* 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;
|
|
}
|
|
|
|
|
|
|
|
|