Add support to estimate file duration.
The code will estimate the file duration if the last block duration is 0. This is not totally correct, but better then what we currently have. BUG=https://bugs.chromium.org/p/webm/issues/detail?id=1100 Change-Id: I8f81df0bd592e6f7b1925fa2637a2e09cf182742
This commit is contained in:
parent
c97e3e7d60
commit
02bc809f9d
@ -3042,6 +3042,7 @@ Segment::Segment()
|
||||
output_cues_(true),
|
||||
accurate_cluster_duration_(false),
|
||||
fixed_size_cluster_timecode_(false),
|
||||
estimate_file_duration_(true),
|
||||
payload_pos_(0),
|
||||
size_position_(0),
|
||||
doc_type_version_(kDefaultDocTypeVersion),
|
||||
@ -3150,6 +3151,10 @@ bool Segment::Init(IMkvWriter* ptr_writer) {
|
||||
writer_cluster_ = ptr_writer;
|
||||
writer_cues_ = ptr_writer;
|
||||
writer_header_ = ptr_writer;
|
||||
memset(&track_frames_written_, 0,
|
||||
sizeof(track_frames_written_[0]) * kMaxTrackNumber);
|
||||
memset(&last_track_timestamp_, 0,
|
||||
sizeof(last_track_timestamp_[0]) * kMaxTrackNumber);
|
||||
return segment_info_.Init();
|
||||
}
|
||||
|
||||
@ -3212,9 +3217,26 @@ bool Segment::Finalize() {
|
||||
chunk_count_++;
|
||||
}
|
||||
|
||||
const double duration =
|
||||
double duration =
|
||||
(static_cast<double>(last_timestamp_) + last_block_duration_) /
|
||||
segment_info_.timecode_scale();
|
||||
if (last_block_duration_ == 0 && estimate_file_duration_) {
|
||||
const int num_tracks = static_cast<int>(tracks_.track_entries_size());
|
||||
for (int i = 0; i < num_tracks; ++i) {
|
||||
if (track_frames_written_[i] < 2)
|
||||
continue;
|
||||
|
||||
// Estimate the duration for the last block of a Track.
|
||||
const double nano_per_frame =
|
||||
static_cast<double>(last_track_timestamp_[i]) /
|
||||
(track_frames_written_[i] - 1);
|
||||
const double track_duration =
|
||||
(last_track_timestamp_[i] + nano_per_frame) /
|
||||
segment_info_.timecode_scale();
|
||||
if (track_duration > duration)
|
||||
duration = track_duration;
|
||||
}
|
||||
}
|
||||
segment_info_.set_duration(duration);
|
||||
if (!segment_info_.Finalize(writer_header_))
|
||||
return false;
|
||||
@ -3460,7 +3482,10 @@ bool Segment::AddGenericFrame(const Frame* frame) {
|
||||
Frame* const new_frame = new (std::nothrow) Frame();
|
||||
if (!new_frame || !new_frame->CopyFrom(*frame))
|
||||
return false;
|
||||
return QueueFrame(new_frame);
|
||||
if (!QueueFrame(new_frame))
|
||||
return false;
|
||||
track_frames_written_[frame->track_number() - 1]++;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!DoNewClusterProcessing(frame->track_number(), frame->timestamp(),
|
||||
@ -3500,6 +3525,7 @@ bool Segment::AddGenericFrame(const Frame* frame) {
|
||||
last_timestamp_ = frame->timestamp();
|
||||
last_track_timestamp_[frame->track_number() - 1] = frame->timestamp();
|
||||
last_block_duration_ = frame->duration();
|
||||
track_frames_written_[frame->track_number() - 1]++;
|
||||
|
||||
if (frame_created)
|
||||
delete frame;
|
||||
|
@ -1683,6 +1683,10 @@ class Segment {
|
||||
Mode mode() const { return mode_; }
|
||||
CuesPosition cues_position() const { return cues_position_; }
|
||||
bool output_cues() const { return output_cues_; }
|
||||
void set_estimate_file_duration(bool estimate_duration) {
|
||||
estimate_file_duration_ = estimate_duration;
|
||||
}
|
||||
bool estimate_file_duration() const { return estimate_file_duration_; }
|
||||
const SegmentInfo* segment_info() const { return &segment_info_; }
|
||||
|
||||
// Returns true when codec IDs are valid for WebM.
|
||||
@ -1842,6 +1846,9 @@ class Segment {
|
||||
// Last timestamp in nanoseconds by track number added to a cluster.
|
||||
uint64_t last_track_timestamp_[kMaxTrackNumber];
|
||||
|
||||
// Number of frames written per track.
|
||||
uint64_t track_frames_written_[kMaxTrackNumber];
|
||||
|
||||
// Maximum time in nanoseconds for a cluster duration. This variable is a
|
||||
// guideline and some clusters may have a longer duration. Default is 30
|
||||
// seconds.
|
||||
@ -1870,6 +1877,9 @@ class Segment {
|
||||
// Flag whether or not to write the Cluster Timecode using exactly 8 bytes.
|
||||
bool fixed_size_cluster_timecode_;
|
||||
|
||||
// Flag whether or not to estimate the file duration.
|
||||
bool estimate_file_duration_;
|
||||
|
||||
// The size of the EBML header, used to validate the header if
|
||||
// WriteEbmlHeader() is called more than once.
|
||||
int32_t ebml_header_size_;
|
||||
|
@ -192,6 +192,7 @@ TEST_F(MuxerTest, AddChapters) {
|
||||
|
||||
TEST_F(MuxerTest, SimpleBlock) {
|
||||
EXPECT_TRUE(SegmentInit(false, false, false));
|
||||
segment_.set_estimate_file_duration(false);
|
||||
AddVideoTrack();
|
||||
|
||||
// Valid Frame
|
||||
@ -220,6 +221,7 @@ TEST_F(MuxerTest, SimpleBlock) {
|
||||
|
||||
TEST_F(MuxerTest, SimpleBlockWithAddGenericFrame) {
|
||||
EXPECT_TRUE(SegmentInit(false, false, false));
|
||||
segment_.set_estimate_file_duration(false);
|
||||
AddVideoTrack();
|
||||
|
||||
Frame frame;
|
||||
@ -303,6 +305,7 @@ TEST_F(MuxerTest, TrackType) {
|
||||
|
||||
TEST_F(MuxerTest, BlockWithAdditional) {
|
||||
EXPECT_TRUE(SegmentInit(false, false, false));
|
||||
segment_.set_estimate_file_duration(false);
|
||||
AddVideoTrack();
|
||||
|
||||
// Valid Frame
|
||||
@ -344,6 +347,7 @@ TEST_F(MuxerTest, BlockWithAdditional) {
|
||||
|
||||
TEST_F(MuxerTest, BlockAdditionalWithAddGenericFrame) {
|
||||
EXPECT_TRUE(SegmentInit(false, false, false));
|
||||
segment_.set_estimate_file_duration(false);
|
||||
AddVideoTrack();
|
||||
|
||||
Frame frame;
|
||||
@ -407,6 +411,7 @@ TEST_F(MuxerTest, SegmentDurationComputation) {
|
||||
|
||||
TEST_F(MuxerTest, ForceNewCluster) {
|
||||
EXPECT_TRUE(SegmentInit(false, false, false));
|
||||
segment_.set_estimate_file_duration(false);
|
||||
AddVideoTrack();
|
||||
|
||||
EXPECT_TRUE(segment_.AddFrame(dummy_data_, kFrameLength, kVideoTrackNumber, 0,
|
||||
@ -429,6 +434,7 @@ TEST_F(MuxerTest, ForceNewCluster) {
|
||||
|
||||
TEST_F(MuxerTest, OutputCues) {
|
||||
EXPECT_TRUE(SegmentInit(true, false, false));
|
||||
segment_.set_estimate_file_duration(false);
|
||||
AddVideoTrack();
|
||||
|
||||
EXPECT_TRUE(
|
||||
@ -449,6 +455,7 @@ TEST_F(MuxerTest, OutputCues) {
|
||||
|
||||
TEST_F(MuxerTest, CuesBeforeClusters) {
|
||||
EXPECT_TRUE(SegmentInit(true, false, false));
|
||||
segment_.set_estimate_file_duration(false);
|
||||
AddVideoTrack();
|
||||
|
||||
EXPECT_TRUE(
|
||||
@ -488,6 +495,7 @@ TEST_F(MuxerTest, CuesBeforeClusters) {
|
||||
|
||||
TEST_F(MuxerTest, MaxClusterSize) {
|
||||
EXPECT_TRUE(SegmentInit(false, false, false));
|
||||
segment_.set_estimate_file_duration(false);
|
||||
AddVideoTrack();
|
||||
const uint64_t kMaxClusterSize = 20;
|
||||
segment_.set_max_cluster_size(kMaxClusterSize);
|
||||
@ -513,6 +521,7 @@ TEST_F(MuxerTest, MaxClusterSize) {
|
||||
|
||||
TEST_F(MuxerTest, MaxClusterDuration) {
|
||||
EXPECT_TRUE(SegmentInit(false, false, false));
|
||||
segment_.set_estimate_file_duration(false);
|
||||
AddVideoTrack();
|
||||
const uint64_t kMaxClusterDuration = 4000000;
|
||||
segment_.set_max_cluster_duration(kMaxClusterDuration);
|
||||
@ -570,6 +579,7 @@ TEST_F(MuxerTest, SetCuesTrackNumber) {
|
||||
|
||||
TEST_F(MuxerTest, BlockWithDiscardPadding) {
|
||||
EXPECT_TRUE(SegmentInit(false, false, false));
|
||||
segment_.set_estimate_file_duration(false);
|
||||
AddAudioTrack();
|
||||
|
||||
int timecode = 1000;
|
||||
@ -593,6 +603,7 @@ TEST_F(MuxerTest, BlockWithDiscardPadding) {
|
||||
|
||||
TEST_F(MuxerTest, AccurateClusterDuration) {
|
||||
EXPECT_TRUE(SegmentInit(false, true, false));
|
||||
segment_.set_estimate_file_duration(false);
|
||||
AddVideoTrack();
|
||||
|
||||
Frame frame;
|
||||
@ -727,6 +738,7 @@ TEST_F(MuxerTest, AccurateClusterDurationWithoutFinalizingCluster) {
|
||||
|
||||
TEST_F(MuxerTest, UseFixedSizeClusterTimecode) {
|
||||
EXPECT_TRUE(SegmentInit(false, false, true));
|
||||
segment_.set_estimate_file_duration(false);
|
||||
AddVideoTrack();
|
||||
|
||||
Frame frame;
|
||||
@ -917,6 +929,29 @@ TEST_F(MuxerTest, Projection) {
|
||||
EXPECT_TRUE(CompareFiles(GetTestFilePath("projection.webm"), filename_));
|
||||
}
|
||||
|
||||
TEST_F(MuxerTest, EstimateDuration) {
|
||||
EXPECT_TRUE(SegmentInit(false, false, false));
|
||||
AddVideoTrack();
|
||||
EXPECT_TRUE(segment_.AddFrame(dummy_data_, kFrameLength, kVideoTrackNumber, 0,
|
||||
false));
|
||||
EXPECT_TRUE(segment_.AddFrame(dummy_data_, kFrameLength, kVideoTrackNumber,
|
||||
2000000, false));
|
||||
EXPECT_TRUE(segment_.AddFrame(dummy_data_, kFrameLength, kVideoTrackNumber,
|
||||
4000000, false));
|
||||
EXPECT_TRUE(segment_.AddFrame(dummy_data_, kFrameLength, kVideoTrackNumber,
|
||||
6000000, false));
|
||||
EXPECT_TRUE(segment_.AddFrame(dummy_data_, kFrameLength, kVideoTrackNumber,
|
||||
8000000, false));
|
||||
EXPECT_TRUE(segment_.AddFrame(dummy_data_, kFrameLength, kVideoTrackNumber,
|
||||
9000000, false));
|
||||
segment_.Finalize();
|
||||
|
||||
CloseWriter();
|
||||
|
||||
EXPECT_TRUE(
|
||||
CompareFiles(GetTestFilePath("estimate_duration.webm"), filename_));
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
|
@ -51,6 +51,7 @@ bool CompareFiles(const std::string& file1, const std::string& file2) {
|
||||
const std::size_t r1 = std::fread(buf1, 1, kBlockSize, f1.get());
|
||||
const std::size_t r2 = std::fread(buf2, 1, kBlockSize, f2.get());
|
||||
|
||||
// TODO(fgalligan): Add output of which byte differs.
|
||||
if (r1 != r2 || std::memcmp(buf1, buf2, r1)) {
|
||||
return 0; // Files are not equal
|
||||
}
|
||||
@ -211,4 +212,4 @@ bool ParseMkvFile(const std::string& webm_file) {
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace test
|
||||
|
BIN
testing/testdata/estimate_duration.webm
vendored
Normal file
BIN
testing/testdata/estimate_duration.webm
vendored
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user