static int cps_seek_timecode(void* data, const Timecode* timecode, TimecodeType type, TimecodeSubType subType) { ClipSource* clipSource = (ClipSource*)data; int64_t originalPosition = -1; int64_t position; /* get position so we can recover is seek is outside the clip boundaries */ if (!msc_get_position(clipSource->targetSource, &originalPosition)) { originalPosition = -1; /* unknown */ } int result = msc_seek_timecode(clipSource->targetSource, timecode, type, subType); if (originalPosition < 0 || result != 0) { return result; } /* check the seek is within the clip boundaries */ if (!msc_get_position(clipSource->targetSource, &position)) { /* TODO: what now? */ /* assume outside - go back to original position */ msc_seek(clipSource->targetSource, originalPosition); return -1; } if (clipSource->duration >= 0) { if (position < clipSource->start || position > clipSource->start + clipSource->duration) { /* outside - go back to original position */ msc_seek(clipSource->targetSource, originalPosition); return -1; } } else if (clipSource->start > 0) { if (position < clipSource->start) { /* outside - go back to original position */ msc_seek(clipSource->targetSource, originalPosition); return -1; } } return result; }
static int mls_seek(void* data, int64_t position) { MultipleMediaSources* multSource = (MultipleMediaSources*)data; MediaSourceElement* ele = &multSource->sources; int seekResult = 0; int syncResult; /* make sure the sources are in sync */ if ((syncResult = sync_sources(multSource)) != 0) { return syncResult; } while (ele != NULL && ele->source != NULL) { if (!SOURCE_IS_DISABLED(ele)) { seekResult = msc_seek(ele->source, position); if (seekResult != 0 ) { break; } } ele = ele->next; } if (seekResult == 0) { /* update sync position */ multSource->syncPosition = position; } return seekResult; }
static int sync_sources(MultipleMediaSources* multSource) { MediaSourceElement* ele = &multSource->sources; int64_t position; int syncResult = 0; while (ele != NULL && ele->source != NULL) { if (!SOURCE_IS_DISABLED(ele)) { if (!msc_get_position(ele->source, &position)) { syncResult = -1; break; } if (position != multSource->syncPosition) { /* seek back to the sync position */ syncResult = msc_seek(ele->source, multSource->syncPosition); if (syncResult != 0) { break; } } } ele = ele->next; } return syncResult; }
static int cps_seek(void* data, int64_t position) { ClipSource* clipSource = (ClipSource*)data; if (clipSource->duration >= 0) { /* check the position is within the clip boundaries */ if (position > clipSource->duration) { return 0; } return msc_seek(clipSource->targetSource, clipSource->start + position); } else if (clipSource->start > 0) { return msc_seek(clipSource->targetSource, clipSource->start + position); } return msc_seek(clipSource->targetSource, position); }
int cps_create(MediaSource* targetSource, const Rational* frameRate, int64_t start, int64_t duration, ClipSource** clipSource) { ClipSource* newClipSource; if (start > 0 && !msc_seek(targetSource, start)) { ml_log_warn("Failed to seek to start of the clip\n"); } CALLOC_ORET(newClipSource, ClipSource, 1); newClipSource->targetSource = targetSource; newClipSource->start = (start < 0) ? 0 : start; newClipSource->duration = duration; newClipSource->frameRate = *frameRate; /* note: frameRate could be 0/0 */ newClipSource->mediaSource.data = newClipSource; newClipSource->mediaSource.is_complete = cps_is_complete; newClipSource->mediaSource.post_complete = cps_post_complete; newClipSource->mediaSource.finalise_blank_source = cps_finalise_blank_source; newClipSource->mediaSource.get_num_streams = cps_get_num_streams; newClipSource->mediaSource.get_stream_info = cps_get_stream_info; newClipSource->mediaSource.set_frame_rate_or_disable = cps_set_frame_rate_or_disable; newClipSource->mediaSource.disable_stream = cps_disable_stream; newClipSource->mediaSource.disable_audio = cps_disable_audio; newClipSource->mediaSource.disable_video = cps_disable_video; newClipSource->mediaSource.stream_is_disabled = cps_stream_is_disabled; newClipSource->mediaSource.read_frame = cps_read_frame; newClipSource->mediaSource.is_seekable = cps_is_seekable; newClipSource->mediaSource.seek = cps_seek; newClipSource->mediaSource.seek_timecode = cps_seek_timecode; newClipSource->mediaSource.get_length = cps_get_length; newClipSource->mediaSource.get_position = cps_get_position; newClipSource->mediaSource.get_available_length = cps_get_available_length; newClipSource->mediaSource.eof = cps_eof; newClipSource->mediaSource.set_source_name = cps_set_source_name; newClipSource->mediaSource.set_clip_id = cps_set_clip_id; newClipSource->mediaSource.close = cps_close; newClipSource->mediaSource.get_buffer_state = cps_get_buffer_state; newClipSource->mediaSource.convert_position = cps_convert_position; *clipSource = newClipSource; return 1; }
static int mls_seek_timecode(void* data, const Timecode* timecode, TimecodeType type, TimecodeSubType subType) { MultipleMediaSources* multSource = (MultipleMediaSources*)data; MediaSourceElement* ele = &multSource->sources; int seekResult = 0; int haveATimedOutResult = 0; int failed = 0; MediaSourceElement* passedEle = NULL; int64_t position; int syncResult; /* make sure the sources are in sync */ if ((syncResult = sync_sources(multSource)) != 0) { return syncResult; } /* find the source that supports and successfully seeks to the timecode */ while (ele != NULL && ele->source != NULL) { if (!SOURCE_IS_DISABLED(ele)) { seekResult = msc_seek_timecode(ele->source, timecode, type, subType); if (seekResult == 0) { passedEle = ele; if (!msc_get_position(ele->source, &position)) { ml_log_error("Failed to get position at seek to timecode\n"); return -1; } break; } else if (seekResult == -2) { haveATimedOutResult = 1; } } ele = ele->next; } if (passedEle == NULL) { /* none of the sources could be seeked to the timecode */ if (haveATimedOutResult) { /* assume that the timed out source could have seeked to the timecode */ return -2; } return -1; } /* try seek to the position corresponding to the timecode for the sources that failed */ ele = &multSource->sources; while (ele != NULL && ele->source != NULL) { if (!SOURCE_IS_DISABLED(ele)) { if (ele != passedEle && msc_seek(ele->source, position) != 0) { failed = 1; break; } } ele = ele->next; } if (!failed) { /* update sync position */ multSource->syncPosition = position; } return !failed ? 0 : -1; }