Compare commits
1 Commits
develop
...
fix/refine
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
42ad02cf31 |
|
|
@ -5791,20 +5791,49 @@ srs_error_t SrsMp4SampleManager::write(SrsMp4TrackFragmentBox *traf, uint64_t dt
|
|||
srs_error_t err = srs_success;
|
||||
|
||||
SrsMp4TrackFragmentRunBox *trun = traf->trun();
|
||||
if (trun == NULL) {
|
||||
trun = new SrsMp4TrackFragmentRunBox();
|
||||
traf->set_trun(trun);
|
||||
}
|
||||
trun->flags_ = SrsMp4TrunFlagsDataOffset | SrsMp4TrunFlagsSampleDuration | SrsMp4TrunFlagsSampleSize | SrsMp4TrunFlagsSampleFlag | SrsMp4TrunFlagsSampleCtsOffset;
|
||||
|
||||
SrsMp4Sample *previous = NULL;
|
||||
|
||||
// ISO_IEC_14496-12-base-format-2012.pdf, 8.8.8.1 page 57
|
||||
// Because trun->flags_ has not include SrsMp4TrunFlagsFirstSample(0x000004),
|
||||
// so trun->first_sample_flags_ is not present, and each SrsMp4TrunEntry has sample_flags_.
|
||||
// ISO_IEC_14496-12-base-format-2012.pdf, 8.8.3.1 page 53 define the sample_flags_'s layout.
|
||||
// int(32) sample_flags = {
|
||||
// bit(4) reserved = 0;
|
||||
// int(2) is_leading;
|
||||
// int(2) sample_depends_on;
|
||||
// int(2) sample_is_depends_on;
|
||||
// int(2) sample_has_redundancy;
|
||||
// bit(3) sample_padding_value;
|
||||
// bit(1) sample_is_non_sync_sample;
|
||||
// int(16) sample_degradation_priority;
|
||||
// }
|
||||
// ISO_IEC_14496-12-base-format-2012.pdf, 8.6.4.1, 8.6.4.3 page 41 define the sample_flags_'s values.
|
||||
// sample_depends_on == 1: this sample does depend on others;
|
||||
// sample_depends_on == 2: this sample does not depend on others;
|
||||
vector<SrsMp4Sample *>::iterator it;
|
||||
for (it = samples_.begin(); it != samples_.end(); ++it) {
|
||||
SrsMp4Sample *sample = *it;
|
||||
SrsMp4TrunEntry *entry = new SrsMp4TrunEntry(trun);
|
||||
|
||||
if (!previous) {
|
||||
previous = sample;
|
||||
entry->sample_flags_ = 0x02000000;
|
||||
if (sample->type_ == SrsFrameTypeVideo) {
|
||||
if (sample->frame_type_ == SrsVideoAvcFrameTypeKeyFrame) {
|
||||
// For video keyframe: no dependencies (sample_depends_on = 2), IS a sync sample (sample_is_non_sync_sample = 0)
|
||||
// ISO 14496-12 section 8.8.3.1: sample_is_non_sync_sample = 0 means this IS a sync sample
|
||||
// This provides equivalent information to being in a sync sample table (stss box)
|
||||
entry->sample_flags_ = 0x02000000 | 0x00000000;
|
||||
} else {
|
||||
// For video non-keyframe: has dependencies (sample_depends_on = 1), NOT a sync sample (sample_is_non_sync_sample = 1)
|
||||
// ISO 14496-12 section 8.8.3.1: sample_is_non_sync_sample = 1 means this is NOT a sync sample
|
||||
entry->sample_flags_ = 0x01000000 | 0x00010000;
|
||||
}
|
||||
} else {
|
||||
entry->sample_flags_ = 0x01000000;
|
||||
// For audio, all samples are independent: no dependencies (sample_depends_on = 2), IS a sync sample (sample_is_non_sync_sample = 0)
|
||||
// ISO 14496-12 section 8.8.3.1: sample_is_non_sync_sample = 0 means this IS a sync sample
|
||||
entry->sample_flags_ = 0x02000000 | 0x00000000;
|
||||
}
|
||||
|
||||
vector<SrsMp4Sample *>::iterator iter = (it + 1);
|
||||
|
|
|
|||
|
|
@ -2595,3 +2595,175 @@ VOID TEST(KernelMp4Test, SrsMp4DvrJitter)
|
|||
EXPECT_EQ(0, jitter.get_first_sample_delta(SrsFrameTypeAudio));
|
||||
}
|
||||
}
|
||||
|
||||
VOID TEST(KernelMp4Test, SrsMp4SampleManagerWrite)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
// Test with video keyframe samples
|
||||
if (true) {
|
||||
SrsMp4SampleManager manager;
|
||||
SrsMp4TrackFragmentBox traf;
|
||||
|
||||
// Create a video keyframe sample
|
||||
SrsMp4Sample *video_sample = new SrsMp4Sample();
|
||||
video_sample->type_ = SrsFrameTypeVideo;
|
||||
video_sample->dts_ = 1000;
|
||||
video_sample->pts_ = 1000;
|
||||
video_sample->tbn_ = 90000;
|
||||
video_sample->frame_type_ = SrsVideoAvcFrameTypeKeyFrame;
|
||||
video_sample->nb_data_ = 100;
|
||||
|
||||
// Add sample to manager
|
||||
manager.append(video_sample);
|
||||
|
||||
// Write samples to traf with appropriate next_dts
|
||||
err = manager.write(&traf, video_sample->dts_ + 1000);
|
||||
HELPER_EXPECT_SUCCESS(err);
|
||||
|
||||
// Verify TRUN box was created with correct entries
|
||||
SrsMp4TrackFragmentRunBox *trun = traf.trun();
|
||||
ASSERT_TRUE(trun != NULL);
|
||||
ASSERT_EQ(1, (int)trun->entries_.size());
|
||||
|
||||
// Verify TRUN entry for video keyframe
|
||||
SrsMp4TrunEntry *entry = trun->entries_.at(0);
|
||||
EXPECT_EQ(1000, entry->sample_duration_);
|
||||
EXPECT_EQ(100, entry->sample_size_);
|
||||
EXPECT_EQ(0, entry->sample_composition_time_offset_);
|
||||
// Keyframe should have sample_depends_on_no and sample_is_non_sync_sample=0 (sync sample)
|
||||
EXPECT_EQ(0, entry->sample_flags_ & 0x00010000);
|
||||
}
|
||||
|
||||
// Test with video non-keyframe samples
|
||||
if (true) {
|
||||
SrsMp4SampleManager manager;
|
||||
SrsMp4TrackFragmentBox traf;
|
||||
|
||||
// Create a video non-keyframe sample
|
||||
SrsMp4Sample *video_sample = new SrsMp4Sample();
|
||||
video_sample->type_ = SrsFrameTypeVideo;
|
||||
video_sample->dts_ = 2000;
|
||||
video_sample->pts_ = 2000;
|
||||
video_sample->tbn_ = 90000;
|
||||
video_sample->frame_type_ = SrsVideoAvcFrameTypeInterFrame;
|
||||
video_sample->nb_data_ = 50;
|
||||
|
||||
// Add sample to manager
|
||||
manager.append(video_sample);
|
||||
|
||||
// Write samples to traf with appropriate next_dts
|
||||
err = manager.write(&traf, video_sample->dts_ + 1000);
|
||||
HELPER_EXPECT_SUCCESS(err);
|
||||
|
||||
// Verify TRUN box was created with correct entries
|
||||
SrsMp4TrackFragmentRunBox *trun = traf.trun();
|
||||
ASSERT_TRUE(trun != NULL);
|
||||
ASSERT_EQ(1, (int)trun->entries_.size());
|
||||
|
||||
// Verify TRUN entry for video non-keyframe
|
||||
SrsMp4TrunEntry *entry = trun->entries_.at(0);
|
||||
EXPECT_EQ(1000, entry->sample_duration_);
|
||||
EXPECT_EQ(50, entry->sample_size_);
|
||||
EXPECT_EQ(0, entry->sample_composition_time_offset_);
|
||||
// Non-keyframe should have sample_depends_on_yes and sample_is_non_sync_sample=1 (non-sync sample)
|
||||
EXPECT_EQ((uint32_t)(0x00010000 | 0x00000000), entry->sample_flags_ & 0x00010000);
|
||||
}
|
||||
|
||||
// Test with audio samples
|
||||
if (true) {
|
||||
SrsMp4SampleManager manager;
|
||||
SrsMp4TrackFragmentBox traf;
|
||||
|
||||
// Create an audio sample
|
||||
SrsMp4Sample *audio_sample = new SrsMp4Sample();
|
||||
audio_sample->type_ = SrsFrameTypeAudio;
|
||||
audio_sample->dts_ = 3000;
|
||||
audio_sample->pts_ = 3000;
|
||||
audio_sample->tbn_ = 44100;
|
||||
audio_sample->nb_data_ = 200;
|
||||
|
||||
// Add sample to manager
|
||||
manager.append(audio_sample);
|
||||
|
||||
// Write samples to traf with appropriate next_dts
|
||||
err = manager.write(&traf, audio_sample->dts_ + 1000);
|
||||
HELPER_EXPECT_SUCCESS(err);
|
||||
|
||||
// Verify TRUN box was created with correct entries
|
||||
SrsMp4TrackFragmentRunBox *trun = traf.trun();
|
||||
ASSERT_TRUE(trun != NULL);
|
||||
ASSERT_EQ(1, (int)trun->entries_.size());
|
||||
|
||||
// Verify TRUN entry for audio sample
|
||||
SrsMp4TrunEntry *entry = trun->entries_.at(0);
|
||||
EXPECT_EQ(1000, entry->sample_duration_);
|
||||
EXPECT_EQ(200, entry->sample_size_);
|
||||
EXPECT_EQ(0, entry->sample_composition_time_offset_);
|
||||
// Audio should have sample_depends_on_no and sample_is_non_sync_sample=0 (sync sample)
|
||||
EXPECT_EQ(0, entry->sample_flags_ & 0x00010000);
|
||||
}
|
||||
|
||||
// Test with multiple samples (video keyframe, video non-keyframe, audio)
|
||||
if (true) {
|
||||
SrsMp4SampleManager manager;
|
||||
SrsMp4TrackFragmentBox traf;
|
||||
|
||||
// Create video keyframe sample
|
||||
SrsMp4Sample *keyframe = new SrsMp4Sample();
|
||||
keyframe->type_ = SrsFrameTypeVideo;
|
||||
keyframe->dts_ = 1000;
|
||||
keyframe->pts_ = 1000;
|
||||
keyframe->tbn_ = 90000;
|
||||
keyframe->frame_type_ = SrsVideoAvcFrameTypeKeyFrame;
|
||||
keyframe->nb_data_ = 100;
|
||||
|
||||
// Create video non-keyframe sample
|
||||
SrsMp4Sample *deltaframe = new SrsMp4Sample();
|
||||
deltaframe->type_ = SrsFrameTypeVideo;
|
||||
deltaframe->dts_ = 2000;
|
||||
deltaframe->pts_ = 2000;
|
||||
deltaframe->tbn_ = 90000;
|
||||
deltaframe->frame_type_ = SrsVideoAvcFrameTypeInterFrame;
|
||||
deltaframe->nb_data_ = 50;
|
||||
|
||||
// Create audio sample
|
||||
SrsMp4Sample *audio = new SrsMp4Sample();
|
||||
audio->type_ = SrsFrameTypeAudio;
|
||||
audio->dts_ = 3000;
|
||||
audio->pts_ = 3000;
|
||||
audio->tbn_ = 44100;
|
||||
audio->nb_data_ = 200;
|
||||
|
||||
// Add samples to manager
|
||||
manager.append(keyframe);
|
||||
manager.append(deltaframe);
|
||||
manager.append(audio);
|
||||
|
||||
// Write samples to traf with appropriate next_dts
|
||||
uint64_t next_dts = audio->dts_ + 1000;
|
||||
err = manager.write(&traf, next_dts);
|
||||
HELPER_EXPECT_SUCCESS(err);
|
||||
|
||||
// Verify TRUN box was created with correct entries
|
||||
SrsMp4TrackFragmentRunBox *trun = traf.trun();
|
||||
ASSERT_TRUE(trun != NULL);
|
||||
ASSERT_EQ(3, (int)trun->entries_.size());
|
||||
|
||||
// Verify each entry
|
||||
SrsMp4TrunEntry *entry1 = trun->entries_.at(0);
|
||||
EXPECT_EQ(1000, entry1->sample_duration_);
|
||||
EXPECT_EQ(100, entry1->sample_size_);
|
||||
EXPECT_EQ(0, entry1->sample_flags_ & 0x00010000); // Keyframe (sample_is_non_sync_sample=0)
|
||||
|
||||
SrsMp4TrunEntry *entry2 = trun->entries_.at(1);
|
||||
EXPECT_EQ(1000, entry2->sample_duration_);
|
||||
EXPECT_EQ(50, entry2->sample_size_);
|
||||
EXPECT_EQ((uint32_t)(0x00010000 | 0x00000000), entry2->sample_flags_ & 0x00010000); // Non-keyframe (sample_is_non_sync_sample=1)
|
||||
|
||||
SrsMp4TrunEntry *entry3 = trun->entries_.at(2);
|
||||
EXPECT_EQ(1000, entry3->sample_duration_);
|
||||
EXPECT_EQ(200, entry3->sample_size_);
|
||||
EXPECT_EQ(0, entry3->sample_flags_ & 0x00010000); // Audio (sample_is_non_sync_sample=0)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user