VP9: Added VP9 IVF container detection and picture data parsing support to bitstream reader. (#519)
* * rocDecode/VP9: Added VP9 IVF containter detection and picture data parsing. * * rocDecode/VP9 bitstream reader: Wording changes based on review comment. * * rocDecode/VP9 IVF parser: Updated change log based on review comment. * * rocDecode/VP9 IVF parser: Bumped up rocDecode version to 0.11.0. * * rocDecode/VP9: Added VP9 IVF containter detection and picture data parsing. * * rocDecode/VP9 bitstream reader: Wording changes based on review comment. * * rocDecode/VP9 IVF parser: Updated change log based on review comment. * * rocDecode/VP9 IVF parser: Bumped up rocDecode version to 0.11.0. * * rocDecode/VP9 IVF parsing: Minor name correction.
This commit is contained in:
@@ -25,6 +25,7 @@ THE SOFTWARE.
|
||||
#include "hevc_defines.h"
|
||||
#include "avc_defines.h"
|
||||
#include "av1_defines.h"
|
||||
#include "vp9_defines.h"
|
||||
#include "roc_video_parser.h"
|
||||
|
||||
RocVideoESParser::RocVideoESParser(const char *input_file_path) {
|
||||
@@ -462,7 +463,7 @@ bool RocVideoESParser::CheckIvfFileHeader(uint8_t *stream) {
|
||||
}
|
||||
}
|
||||
|
||||
int RocVideoESParser::GetPicDataIvfAv1(uint8_t **p_pic_data, int *pic_size) {
|
||||
int RocVideoESParser::GetPicDataIvf(uint8_t **p_pic_data, int *pic_size) {
|
||||
uint8_t frame_header[12];
|
||||
pic_data_size_ = 0;
|
||||
if (ReadBytes(curr_byte_offset_, 12, frame_header)) {
|
||||
@@ -491,7 +492,8 @@ int RocVideoESParser::GetPicData(uint8_t **p_pic_data, int *pic_size, int64_t *p
|
||||
return GetPicDataAvcHevc(p_pic_data, pic_size);
|
||||
case kStreamTypeAv1Elementary:
|
||||
return GetPicDataAv1(p_pic_data, pic_size);
|
||||
case kStreamTypeAv1Ivf: {
|
||||
case kStreamTypeAv1Ivf:
|
||||
case kStreamTypeVp9Ivf: {
|
||||
if (!ivf_file_header_read_) {
|
||||
uint8_t file_header[32];
|
||||
ReadBytes(curr_byte_offset_, 32, file_header);
|
||||
@@ -499,7 +501,7 @@ int RocVideoESParser::GetPicData(uint8_t **p_pic_data, int *pic_size, int64_t *p
|
||||
SetReadPointer(curr_byte_offset_);
|
||||
ivf_file_header_read_ = true;
|
||||
}
|
||||
return GetPicDataIvfAv1(p_pic_data, pic_size);
|
||||
return GetPicDataIvf(p_pic_data, pic_size);
|
||||
}
|
||||
default: {
|
||||
*p_pic_data = pic_data_.data();
|
||||
@@ -518,6 +520,8 @@ rocDecVideoCodec RocVideoESParser::GetCodecId() {
|
||||
case kStreamTypeAv1Elementary:
|
||||
case kStreamTypeAv1Ivf:
|
||||
return rocDecVideoCodec_AV1;
|
||||
case kStreamTypeVp9Ivf:
|
||||
return rocDecVideoCodec_VP9;
|
||||
default:
|
||||
return rocDecVideoCodec_NumCodecs;
|
||||
}
|
||||
@@ -540,41 +544,53 @@ int RocVideoESParser::ProbeStreamType() {
|
||||
for (int i = kStreamTypeAvcElementary; i < kStreamTypeNumSupported; i++) {
|
||||
int curr_score = 0;
|
||||
switch (i) {
|
||||
case kStreamTypeAvcElementary:
|
||||
case kStreamTypeAvcElementary: {
|
||||
curr_score = CheckAvcEStream(stream_buf, stream_size);
|
||||
if (curr_score > STREAM_TYPE_SCORE_THRESHOLD && curr_score > stream_type_score) {
|
||||
stream_type = kStreamTypeAvcElementary;
|
||||
stream_type_score = curr_score;
|
||||
}
|
||||
break;
|
||||
case kStreamTypeHevcElementary:
|
||||
}
|
||||
case kStreamTypeHevcElementary: {
|
||||
curr_score = CheckHevcEStream(stream_buf, stream_size);
|
||||
if (curr_score > STREAM_TYPE_SCORE_THRESHOLD && curr_score > stream_type_score) {
|
||||
stream_type = kStreamTypeHevcElementary;
|
||||
stream_type_score = curr_score;
|
||||
}
|
||||
break;
|
||||
case kStreamTypeAv1Elementary:
|
||||
}
|
||||
case kStreamTypeAv1Elementary: {
|
||||
curr_score = CheckAv1EStream(stream_buf, stream_size);
|
||||
if (curr_score > STREAM_TYPE_SCORE_THRESHOLD && curr_score > stream_type_score) {
|
||||
stream_type = kStreamTypeAv1Elementary;
|
||||
stream_type_score = curr_score;
|
||||
}
|
||||
break;
|
||||
case kStreamTypeAv1Ivf:
|
||||
}
|
||||
case kStreamTypeAv1Ivf: {
|
||||
curr_score = CheckIvfAv1Stream(stream_buf, stream_size);
|
||||
if (curr_score > STREAM_TYPE_SCORE_THRESHOLD && curr_score > stream_type_score) {
|
||||
stream_type = kStreamTypeAv1Ivf;
|
||||
stream_type_score = curr_score;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kStreamTypeVp9Ivf: {
|
||||
curr_score = CheckIvfVp9Stream(stream_buf, stream_size);
|
||||
if (curr_score > STREAM_TYPE_SCORE_THRESHOLD && curr_score > stream_type_score) {
|
||||
stream_type = kStreamTypeVp9Ivf;
|
||||
stream_type_score = curr_score;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (stream_buf) {
|
||||
free(stream_buf);
|
||||
}
|
||||
p_stream_file_.seekg (0, std::ios::beg);
|
||||
p_stream_file_.seekg(0, std::ios::beg);
|
||||
return stream_type;
|
||||
}
|
||||
|
||||
@@ -1142,4 +1158,85 @@ int RocVideoESParser::CheckIvfAv1Stream(uint8_t *p_stream, int stream_size) {
|
||||
score = 0;
|
||||
}
|
||||
return score;
|
||||
}
|
||||
|
||||
int RocVideoESParser::CheckVp9EStream(uint8_t *p_stream, int stream_size) {
|
||||
int score = 0;
|
||||
int curr_offset = 0; // byte offset
|
||||
size_t offset = 0; // bit offset
|
||||
Vp9UncompressedHeader uncomp_header;
|
||||
|
||||
uncomp_header.frame_marker = Parser::ReadBits(p_stream, offset, 2);
|
||||
if (uncomp_header.frame_marker != 2) {
|
||||
return 0;
|
||||
}
|
||||
uncomp_header.profile_low_bit = Parser::GetBit(p_stream, offset);
|
||||
uncomp_header.profile_high_bit = Parser::GetBit(p_stream, offset);
|
||||
uncomp_header.profile = (uncomp_header.profile_high_bit << 1) + uncomp_header.profile_low_bit;
|
||||
if (uncomp_header.profile == 3) {
|
||||
uncomp_header.reserved_zero = Parser::GetBit(p_stream, offset);
|
||||
if (uncomp_header.reserved_zero) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
uncomp_header.show_existing_frame = Parser::GetBit(p_stream, offset);
|
||||
if (uncomp_header.show_existing_frame) {
|
||||
return 0;
|
||||
}
|
||||
uncomp_header.frame_type = Parser::GetBit(p_stream, offset);
|
||||
uncomp_header.show_frame = Parser::GetBit(p_stream, offset);
|
||||
uncomp_header.error_resilient_mode = Parser::GetBit(p_stream, offset);
|
||||
if (uncomp_header.frame_type == kVp9KeyFrame) {
|
||||
uncomp_header.frame_sync_code.frame_sync_byte_0 = Parser::ReadBits(p_stream, offset, 8);
|
||||
if (uncomp_header.frame_sync_code.frame_sync_byte_0 != 0x49) {
|
||||
return 0;
|
||||
}
|
||||
uncomp_header.frame_sync_code.frame_sync_byte_1 = Parser::ReadBits(p_stream, offset, 8);
|
||||
if (uncomp_header.frame_sync_code.frame_sync_byte_1 != 0x83) {
|
||||
return 0;
|
||||
}
|
||||
uncomp_header.frame_sync_code.frame_sync_byte_2 = Parser::ReadBits(p_stream, offset, 8);
|
||||
if (uncomp_header.frame_sync_code.frame_sync_byte_2 != 0x42) {
|
||||
return 0;
|
||||
}
|
||||
score = 100;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return score;
|
||||
}
|
||||
|
||||
int RocVideoESParser::CheckIvfVp9Stream(uint8_t *p_stream, int stream_size) {
|
||||
static const char *IVF_SIGNATURE = "DKIF";
|
||||
static const char *VP9_FourCC = "VP90";
|
||||
static const int IvfFileHeaderSize = 32;
|
||||
static const int IvfFrameHeaderSize = 12;
|
||||
uint8_t *ptr = p_stream;
|
||||
int score = 0;
|
||||
|
||||
// bytes 0-3: signature
|
||||
if (memcmp(IVF_SIGNATURE, ptr, 4) == 0) {
|
||||
ptr += 4;
|
||||
// bytes 4-5: version (should be 0). Little Endian.
|
||||
int ivf_version = ptr[0] | (ptr[1] << 8);
|
||||
if (ivf_version != 0) {
|
||||
score = 0;
|
||||
} else {
|
||||
ptr += 4;
|
||||
// bytes 8-11: codec FourCC (e.g., 'VP90')
|
||||
if (memcmp(VP9_FourCC, ptr, 4)) {
|
||||
score = 0;
|
||||
} else {
|
||||
ptr = p_stream + IvfFileHeaderSize;
|
||||
int frame_size = ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
|
||||
ptr += IvfFrameHeaderSize;
|
||||
int size = stream_size - IvfFileHeaderSize - IvfFrameHeaderSize;
|
||||
size = frame_size < size ? frame_size : size;
|
||||
score = CheckVp9EStream(ptr, size);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
score = 0;
|
||||
}
|
||||
return score;
|
||||
}
|
||||
@@ -36,6 +36,7 @@ enum {
|
||||
kStreamTypeHevcElementary,
|
||||
kStreamTypeAv1Elementary,
|
||||
kStreamTypeAv1Ivf,
|
||||
kStreamTypeVp9Ivf,
|
||||
kStreamTypeNumSupported
|
||||
} StreamFileType;
|
||||
|
||||
@@ -110,11 +111,11 @@ class RocVideoESParser {
|
||||
*/
|
||||
int GetPicDataAv1(uint8_t **p_pic_data, int *pic_size);
|
||||
|
||||
/*! \brief Function to retrieve the bitstream of a temporal unit for AV1 from IVF container
|
||||
/*! \brief Function to retrieve the bitstream of a frame from IVF container
|
||||
* \param [out] p_pic_data Pointer to the picture data
|
||||
* \param [out] pic_size Size of the picture in bytes
|
||||
*/
|
||||
int GetPicDataIvfAv1(uint8_t **p_pic_data, int *pic_size);
|
||||
int GetPicDataIvf(uint8_t **p_pic_data, int *pic_size);
|
||||
|
||||
/*! \brief Function to read bitstream from file and fill into the ring buffer.
|
||||
* \return Number of bytes read from file.
|
||||
@@ -226,6 +227,20 @@ class RocVideoESParser {
|
||||
*/
|
||||
int CheckIvfAv1Stream(uint8_t *p_stream, int stream_size);
|
||||
|
||||
/*! \brief Function to check the likelihood of a stream to be a VP9 elementary stream.
|
||||
* \param [in] p_stream Pointer to the stream
|
||||
* \param [in] stream_size Size of the stream in bytes
|
||||
* \return The likelihood score
|
||||
*/
|
||||
int CheckVp9EStream(uint8_t *p_stream, int stream_size);
|
||||
|
||||
/*! \brief Function to check the likelihood of a stream to be an IVF container of VP9 elementary stream.
|
||||
* \param [in] p_stream Pointer to the stream
|
||||
* \param [in] stream_size Size of the stream in bytes
|
||||
* \return The likelihood score
|
||||
*/
|
||||
int CheckIvfVp9Stream(uint8_t *p_stream, int stream_size);
|
||||
|
||||
/*! \brief Function to read variable length unsigned n-bit number appearing directly in the bitstream. 4.10.3. uvlc().
|
||||
* \param [in] p_stream Bit stream pointer
|
||||
* \param [in] bit_offset Starting bit offset
|
||||
|
||||
Reference in New Issue
Block a user