/*************************************************************************************** * * 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 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; }