You've already forked libopenshot
mirror of
https://github.com/OpenShot/libopenshot.git
synced 2026-06-08 22:17:28 -07:00
Preserve audio-only reader dimensions on pasted clips
-Set the parent timeline before hydrating clips inserted through JSON diffs, matching full project JSON load behavior. This lets copied/pasted clips expose timeline context while their nested readers are rebuilt. -Avoid clobbering valid stored dimensions for audio-only FFmpeg readers with the 720x480 fallback. The fallback is now only used when width or height are missing, while parent timeline preview dimensions can still override when available. -Add regression coverage for audio-only FFmpegReader JSON hydration and timeline JSON-diff insertion preserving 1280x720 dimensions.
This commit is contained in:
@@ -1000,8 +1000,10 @@ void FFmpegReader::UpdateAudioInfo() {
|
||||
info.fps.den = 1;
|
||||
info.video_timebase.num = 1;
|
||||
info.video_timebase.den = 30;
|
||||
info.width = 720;
|
||||
info.height = 480;
|
||||
if (info.width <= 0 || info.height <= 0) {
|
||||
info.width = 720;
|
||||
info.height = 480;
|
||||
}
|
||||
|
||||
// Use timeline to set correct width & height (if any)
|
||||
Clip *parent = static_cast<Clip *>(ParentClip());
|
||||
|
||||
@@ -1486,6 +1486,10 @@ void Timeline::apply_json_to_clips(Json::Value change) {
|
||||
// Keep track of allocated clip objects
|
||||
allocated_clips.insert(clip);
|
||||
|
||||
// Match full timeline JSON loading: parent timeline must be available
|
||||
// before clip JSON can inflate nested readers/effects.
|
||||
clip->ParentTimeline(this);
|
||||
|
||||
// Set properties of clip from JSON
|
||||
clip->SetJsonValue(change["value"]);
|
||||
|
||||
|
||||
@@ -143,6 +143,36 @@ TEST_CASE( "Check_Audio_File", "[libopenshot][ffmpegreader]" )
|
||||
r.Close();
|
||||
}
|
||||
|
||||
TEST_CASE( "Audio_Only_SetJson_Preserves_Stored_Dimensions", "[libopenshot][ffmpegreader][json]" )
|
||||
{
|
||||
std::stringstream path;
|
||||
path << TEST_MEDIA_PATH << "piano.wav";
|
||||
|
||||
FFmpegReader r(path.str());
|
||||
std::stringstream json;
|
||||
json << "{\"type\":\"FFmpegReader\","
|
||||
<< "\"path\":\"" << path.str() << "\","
|
||||
<< "\"has_audio\":true,"
|
||||
<< "\"has_video\":false,"
|
||||
<< "\"width\":1280,"
|
||||
<< "\"height\":720,"
|
||||
<< "\"fps\":{\"num\":30,\"den\":1},"
|
||||
<< "\"sample_rate\":44100,"
|
||||
<< "\"channels\":2,"
|
||||
<< "\"channel_layout\":3,"
|
||||
<< "\"duration\":1.0}";
|
||||
|
||||
r.SetJson(json.str());
|
||||
r.Open();
|
||||
|
||||
CHECK(r.info.has_audio);
|
||||
CHECK_FALSE(r.info.has_video);
|
||||
CHECK(r.info.width == 1280);
|
||||
CHECK(r.info.height == 720);
|
||||
CHECK(r.GetFrame(1)->GetWidth() == 1280);
|
||||
CHECK(r.GetFrame(1)->GetHeight() == 720);
|
||||
}
|
||||
|
||||
TEST_CASE( "Check_Video_File", "[libopenshot][ffmpegreader]" )
|
||||
{
|
||||
// Create a reader
|
||||
|
||||
@@ -480,6 +480,48 @@ TEST_CASE("ReaderInfo constructor", "[libopenshot][timeline]")
|
||||
CHECK(r1->info.channel_layout == t1.info.channel_layout);
|
||||
}
|
||||
|
||||
TEST_CASE("JSON diff insert keeps audio-only clip at stored timeline dimensions", "[libopenshot][timeline][json]")
|
||||
{
|
||||
std::stringstream path;
|
||||
path << TEST_MEDIA_PATH << "piano.wav";
|
||||
|
||||
Timeline t(1280, 720, Fraction(30, 1), 44100, 2, LAYOUT_STEREO);
|
||||
std::stringstream diff;
|
||||
diff << "[{\"type\":\"insert\",\"key\":[\"clips\"],\"value\":{"
|
||||
<< "\"id\":\"audio-copy\","
|
||||
<< "\"position\":0,"
|
||||
<< "\"start\":0,"
|
||||
<< "\"end\":1,"
|
||||
<< "\"duration\":1,"
|
||||
<< "\"layer\":1,"
|
||||
<< "\"reader\":{\"type\":\"FFmpegReader\","
|
||||
<< "\"path\":\"" << path.str() << "\","
|
||||
<< "\"has_audio\":true,"
|
||||
<< "\"has_video\":false,"
|
||||
<< "\"width\":1280,"
|
||||
<< "\"height\":720,"
|
||||
<< "\"fps\":{\"num\":30,\"den\":1},"
|
||||
<< "\"sample_rate\":44100,"
|
||||
<< "\"channels\":2,"
|
||||
<< "\"channel_layout\":3,"
|
||||
<< "\"duration\":1.0}"
|
||||
<< "}}]";
|
||||
|
||||
t.ApplyJsonDiff(diff.str());
|
||||
|
||||
std::list<Clip*> clips = t.Clips();
|
||||
REQUIRE(clips.size() == 1);
|
||||
Clip* clip = clips.front();
|
||||
CHECK(clip->ParentTimeline() == &t);
|
||||
CHECK(clip->Reader()->info.width == 1280);
|
||||
CHECK(clip->Reader()->info.height == 720);
|
||||
|
||||
std::shared_ptr<Frame> frame = t.GetFrame(1);
|
||||
REQUIRE(frame);
|
||||
CHECK(frame->GetWidth() == 1280);
|
||||
CHECK(frame->GetHeight() == 720);
|
||||
}
|
||||
|
||||
TEST_CASE( "width and height functions", "[libopenshot][timeline]" )
|
||||
{
|
||||
Fraction fps(30000,1000);
|
||||
|
||||
Reference in New Issue
Block a user