Generate tkhd and pasp boxes properly with non-square pixels
- Width/Height in tkhd box should be display resolution instead of coded resolution. - pasp was not generated earlier. - Assuming SAR as 1:1 if it failed to be extracted successfully. - Also update test files for mp4_media_parser_unittest. This fixes Issue #35. Change-Id: Iedbe6a44465aac6723b6ea2de30aed180821eccd
This commit is contained in:
parent
4f60bfc6c3
commit
e5b6096857
|
@ -83,6 +83,11 @@ VideoStreamInfo::VideoStreamInfo(int track_id,
|
||||||
DVLOG_IF(2, pixel_width_ == 0 || pixel_height_ == 0)
|
DVLOG_IF(2, pixel_width_ == 0 || pixel_height_ == 0)
|
||||||
<< "Failed to extract sar_width and sar_height.";
|
<< "Failed to extract sar_width and sar_height.";
|
||||||
}
|
}
|
||||||
|
if (pixel_width_ == 0 || pixel_height_ == 0) {
|
||||||
|
LOG(WARNING) << "SAR is not extracted successfully. Assuming 1:1.";
|
||||||
|
pixel_width_ = 1;
|
||||||
|
pixel_height_ = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoStreamInfo::~VideoStreamInfo() {}
|
VideoStreamInfo::~VideoStreamInfo() {}
|
||||||
|
|
|
@ -372,9 +372,6 @@ bool TrackHeader::ReadWrite(BoxBuffer* buffer) {
|
||||||
// Set default value for volume, if track is audio, 0x100 else 0.
|
// Set default value for volume, if track is audio, 0x100 else 0.
|
||||||
if (volume == -1)
|
if (volume == -1)
|
||||||
volume = (width != 0 && height != 0) ? 0 : 0x100;
|
volume = (width != 0 && height != 0) ? 0 : 0x100;
|
||||||
// Convert integer to 16.16 fix point.
|
|
||||||
width <<= 16;
|
|
||||||
height <<= 16;
|
|
||||||
}
|
}
|
||||||
std::vector<uint8_t> matrix(kUnityMatrix,
|
std::vector<uint8_t> matrix(kUnityMatrix,
|
||||||
kUnityMatrix + arraysize(kUnityMatrix));
|
kUnityMatrix + arraysize(kUnityMatrix));
|
||||||
|
@ -386,9 +383,6 @@ bool TrackHeader::ReadWrite(BoxBuffer* buffer) {
|
||||||
buffer->ReadWriteVector(&matrix, matrix.size()) &&
|
buffer->ReadWriteVector(&matrix, matrix.size()) &&
|
||||||
buffer->ReadWriteUInt32(&width) &&
|
buffer->ReadWriteUInt32(&width) &&
|
||||||
buffer->ReadWriteUInt32(&height));
|
buffer->ReadWriteUInt32(&height));
|
||||||
// Convert 16.16 fixed point to integer.
|
|
||||||
width >>= 16;
|
|
||||||
height >>= 16;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1001,8 +995,7 @@ bool VideoSampleEntry::ReadWrite(BoxBuffer* buffer) {
|
||||||
buffer->ReadWriteUInt16(&video_depth) &&
|
buffer->ReadWriteUInt16(&video_depth) &&
|
||||||
buffer->ReadWriteInt16(&predefined));
|
buffer->ReadWriteInt16(&predefined));
|
||||||
|
|
||||||
RCHECK(buffer->PrepareChildren() &&
|
RCHECK(buffer->PrepareChildren());
|
||||||
buffer->TryReadWriteChild(&pixel_aspect));
|
|
||||||
|
|
||||||
if (format == FOURCC_ENCV) {
|
if (format == FOURCC_ENCV) {
|
||||||
if (buffer->Reading()) {
|
if (buffer->Reading()) {
|
||||||
|
@ -1021,6 +1014,7 @@ bool VideoSampleEntry::ReadWrite(BoxBuffer* buffer) {
|
||||||
(format == FOURCC_ENCV && sinf.format.format == FOURCC_AVC1)) {
|
(format == FOURCC_ENCV && sinf.format.format == FOURCC_AVC1)) {
|
||||||
RCHECK(buffer->ReadWriteChild(&avcc));
|
RCHECK(buffer->ReadWriteChild(&avcc));
|
||||||
}
|
}
|
||||||
|
RCHECK(buffer->TryReadWriteChild(&pixel_aspect));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -134,6 +134,8 @@ struct TrackHeader : FullBox {
|
||||||
int16_t layer;
|
int16_t layer;
|
||||||
int16_t alternate_group;
|
int16_t alternate_group;
|
||||||
int16_t volume;
|
int16_t volume;
|
||||||
|
// width and height specify the track's visual presentation size as
|
||||||
|
// fixed-point 16.16 values.
|
||||||
uint32_t width;
|
uint32_t width;
|
||||||
uint32_t height;
|
uint32_t height;
|
||||||
};
|
};
|
||||||
|
|
|
@ -114,15 +114,13 @@ TEST_F(MP4MediaParserTest, UnalignedAppend) {
|
||||||
// the container has a 'pasp' box.
|
// the container has a 'pasp' box.
|
||||||
TEST_F(MP4MediaParserTest, PixelWidthPixelHeightFromPaspBox) {
|
TEST_F(MP4MediaParserTest, PixelWidthPixelHeightFromPaspBox) {
|
||||||
// This content has a 'pasp' box that has the aspect ratio.
|
// This content has a 'pasp' box that has the aspect ratio.
|
||||||
EXPECT_TRUE(ParseMP4File("bear-1280x720.mp4", 512));
|
EXPECT_TRUE(ParseMP4File("bear-640x360-non_square_pixel-with_pasp.mp4", 512));
|
||||||
|
|
||||||
// Track ID 2 has the video stream which should have pixel width and height
|
const int kVideoTrackId = 1;
|
||||||
// both 1.
|
EXPECT_EQ(8u,
|
||||||
const int kVideoTrackId = 2;
|
|
||||||
EXPECT_EQ(1u,
|
|
||||||
reinterpret_cast<VideoStreamInfo*>(stream_map_[kVideoTrackId].get())
|
reinterpret_cast<VideoStreamInfo*>(stream_map_[kVideoTrackId].get())
|
||||||
->pixel_width());
|
->pixel_width());
|
||||||
EXPECT_EQ(1u,
|
EXPECT_EQ(9u,
|
||||||
reinterpret_cast<VideoStreamInfo*>(stream_map_[kVideoTrackId].get())
|
reinterpret_cast<VideoStreamInfo*>(stream_map_[kVideoTrackId].get())
|
||||||
->pixel_height());
|
->pixel_height());
|
||||||
}
|
}
|
||||||
|
@ -132,13 +130,11 @@ TEST_F(MP4MediaParserTest, PixelWidthPixelHeightFromPaspBox) {
|
||||||
// No 'pasp' box.
|
// No 'pasp' box.
|
||||||
TEST_F(MP4MediaParserTest,
|
TEST_F(MP4MediaParserTest,
|
||||||
PixelWidthPixelHeightFromAVCDecoderConfigurationRecord) {
|
PixelWidthPixelHeightFromAVCDecoderConfigurationRecord) {
|
||||||
// This file doesn't have pasp. SPS for the video has
|
// This file doesn't have pasp. The stream should extract pixel width and
|
||||||
// sar_width = sar_height = 0. So the stream info should return 1 for both
|
// height from SPS.
|
||||||
// pixel_width and pixel_height.
|
EXPECT_TRUE(
|
||||||
EXPECT_TRUE(ParseMP4File("hb2_v_frag.mp4", 512));
|
ParseMP4File("bear-640x360-non_square_pixel-without_pasp.mp4", 512));
|
||||||
|
|
||||||
// Track ID 1 has the video stream which should have pixel width and height
|
|
||||||
// both 1.
|
|
||||||
const int kVideoTrackId = 1;
|
const int kVideoTrackId = 1;
|
||||||
EXPECT_EQ(8u,
|
EXPECT_EQ(8u,
|
||||||
reinterpret_cast<VideoStreamInfo*>(stream_map_[kVideoTrackId].get())
|
reinterpret_cast<VideoStreamInfo*>(stream_map_[kVideoTrackId].get())
|
||||||
|
@ -156,10 +152,8 @@ TEST_F(MP4MediaParserTest,
|
||||||
// This file doesn't have pasp. SPS for the video has
|
// This file doesn't have pasp. SPS for the video has
|
||||||
// sar_width = sar_height = 0. So the stream info should return 1 for both
|
// sar_width = sar_height = 0. So the stream info should return 1 for both
|
||||||
// pixel_width and pixel_height.
|
// pixel_width and pixel_height.
|
||||||
EXPECT_TRUE(ParseMP4File("bear-1280x720-av_frag.mp4", 512));
|
EXPECT_TRUE(ParseMP4File("bear-640x360-av_frag.mp4", 512));
|
||||||
|
|
||||||
// Track ID 1 has the video stream which should have pixel width and height
|
|
||||||
// both 1.
|
|
||||||
const int kVideoTrackId = 1;
|
const int kVideoTrackId = 1;
|
||||||
EXPECT_EQ(1u,
|
EXPECT_EQ(1u,
|
||||||
reinterpret_cast<VideoStreamInfo*>(stream_map_[kVideoTrackId].get())
|
reinterpret_cast<VideoStreamInfo*>(stream_map_[kVideoTrackId].get())
|
||||||
|
|
|
@ -159,8 +159,14 @@ void MP4Muxer::GenerateVideoTrak(const VideoStreamInfo* video_info,
|
||||||
uint32_t track_id) {
|
uint32_t track_id) {
|
||||||
InitializeTrak(video_info, trak);
|
InitializeTrak(video_info, trak);
|
||||||
|
|
||||||
trak->header.width = video_info->width();
|
// width and height specify the track's visual presentation size as
|
||||||
trak->header.height = video_info->height();
|
// fixed-point 16.16 values.
|
||||||
|
const double sample_aspect_ratio =
|
||||||
|
static_cast<double>(video_info->pixel_width()) /
|
||||||
|
video_info->pixel_height();
|
||||||
|
trak->header.width = video_info->width() * sample_aspect_ratio * 0x10000;
|
||||||
|
trak->header.height = video_info->height() * 0x10000;
|
||||||
|
|
||||||
trak->media.handler.type = kVideo;
|
trak->media.handler.type = kVideo;
|
||||||
|
|
||||||
VideoSampleEntry video;
|
VideoSampleEntry video;
|
||||||
|
@ -168,6 +174,10 @@ void MP4Muxer::GenerateVideoTrak(const VideoStreamInfo* video_info,
|
||||||
video.width = video_info->width();
|
video.width = video_info->width();
|
||||||
video.height = video_info->height();
|
video.height = video_info->height();
|
||||||
video.avcc.data = video_info->extra_data();
|
video.avcc.data = video_info->extra_data();
|
||||||
|
if (video_info->pixel_width() != 1 || video_info->pixel_height() != 1) {
|
||||||
|
video.pixel_aspect.h_spacing = video_info->pixel_width();
|
||||||
|
video.pixel_aspect.v_spacing = video_info->pixel_height();
|
||||||
|
}
|
||||||
|
|
||||||
SampleDescription& sample_description =
|
SampleDescription& sample_description =
|
||||||
trak->media.information.sample_table.description;
|
trak->media.information.sample_table.description;
|
||||||
|
|
|
@ -44,6 +44,10 @@ bear-640x360-v_frag-cenc.mp4 - A fragmented MP4 version of the video track of be
|
||||||
[1] 30313233343536373839303132333435
|
[1] 30313233343536373839303132333435
|
||||||
[2] ebdd62f16814d27b68ef122afce4ae3c
|
[2] ebdd62f16814d27b68ef122afce4ae3c
|
||||||
|
|
||||||
|
// Non square pixels.
|
||||||
|
bear-640x360-non_square_pixel-with_pasp.mp4 - A non-square pixel version of the video track of bear-640x360.mp4 with PixelAspectRatio box.
|
||||||
|
bear-640x360-non_square_pixel-without_pasp.mp4 - A non-square pixel version of the video track of bear-640x360.mp4 without PixelAspectRatio box.
|
||||||
|
|
||||||
// Container Tests (additional containers derived from bear.ogv)
|
// Container Tests (additional containers derived from bear.ogv)
|
||||||
bear.ac3 -- created using "avconv -i bear.ogv -f ac3 -b 192k bear.ac3".
|
bear.ac3 -- created using "avconv -i bear.ogv -f ac3 -b 192k bear.ac3".
|
||||||
bear.adts -- created using "avconv -i bear.ogv -f adts -strict experimental bear.adts".
|
bear.adts -- created using "avconv -i bear.ogv -f adts -strict experimental bear.adts".
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -97,7 +97,7 @@
|
||||||
'media/filters/filters.gyp:filters_unittest',
|
'media/filters/filters.gyp:filters_unittest',
|
||||||
'media/formats/mp2t/mp2t.gyp:mp2t_unittest',
|
'media/formats/mp2t/mp2t.gyp:mp2t_unittest',
|
||||||
'media/formats/mp4/mp4.gyp:mp4_unittest',
|
'media/formats/mp4/mp4.gyp:mp4_unittest',
|
||||||
# 'media/formats/wvm/wvm.gyp:wvm_unittest',
|
'media/formats/wvm/wvm.gyp:wvm_unittest',
|
||||||
'mpd/mpd.gyp:mpd_unittest',
|
'mpd/mpd.gyp:mpd_unittest',
|
||||||
'packager_test',
|
'packager_test',
|
||||||
],
|
],
|
||||||
|
|
Loading…
Reference in New Issue