diff --git a/ffmpeg/decoder.c b/ffmpeg/decoder.c index c19ff7f446..edb12a90e9 100755 --- a/ffmpeg/decoder.c +++ b/ffmpeg/decoder.c @@ -354,6 +354,7 @@ int open_input(input_params *params, struct input_ctx *ctx) int ret = 0; ctx->transmuxing = params->transmuxing; + ctx->loop = params->loop; // open demuxer/ open demuxer AVDictionary **demuxer_opts = NULL; diff --git a/ffmpeg/decoder.h b/ffmpeg/decoder.h index 4088682242..a0e361be4d 100755 --- a/ffmpeg/decoder.h +++ b/ffmpeg/decoder.h @@ -52,6 +52,8 @@ struct input_ctx { // Transmuxing mode. Close output in lpms_transcode_stop instead of // at the end of lpms_transcode call. int transmuxing; + // How many times should the input be looped? -1 for forever. + int loop; // In HW transcoding, demuxer is opened once and used, // so it is necessary to check whether the input pixel format does not change in the middle. enum AVPixelFormat last_format; diff --git a/ffmpeg/ffmpeg.go b/ffmpeg/ffmpeg.go index 76c743fdb0..4d4842c2d2 100755 --- a/ffmpeg/ffmpeg.go +++ b/ffmpeg/ffmpeg.go @@ -98,6 +98,8 @@ type TranscodeOptionsIn struct { Device string Transmuxing bool Profile VideoProfile + Demuxer ComponentOptions + Loop int } type TranscodeOptions struct { @@ -944,8 +946,16 @@ func (t *Transcoder) Transcode(input *TranscodeOptionsIn, ps []TranscodeOptions) var demuxerOpts C.component_opts ext := filepath.Ext(input.Fname) - // If the input has an image file extension setup the image2 demuxer - if ext == ".png" { + if input.Demuxer.Name != "" { + // If we have a specified demuxer, use that + demuxerName := C.CString(input.Demuxer.Name) + defer C.free(unsafe.Pointer(demuxerName)) + demuxerOpts = C.component_opts{ + name: demuxerName, + opts: newAVOpts(input.Demuxer.Opts), + } + } else if ext == ".png" { + // If the input has an image file extension setup the image2 demuxer image2 := C.CString("image2") defer C.free(unsafe.Pointer(image2)) @@ -966,8 +976,15 @@ func (t *Transcoder) Transcode(input *TranscodeOptionsIn, ps []TranscodeOptions) } } - inp := &C.input_params{fname: fname, hw_type: hw_type, device: device, xcoderParams: xcoderParams, - handle: t.handle, demuxer: demuxerOpts} + inp := &C.input_params{ + fname: fname, + hw_type: hw_type, + device: device, + xcoderParams: xcoderParams, + handle: t.handle, + demuxer: demuxerOpts, + loop: C.int(input.Loop), + } if input.Transmuxing { inp.transmuxing = 1 } diff --git a/ffmpeg/transcoder.c b/ffmpeg/transcoder.c index dfc0807aa5..3f87a88d71 100755 --- a/ffmpeg/transcoder.c +++ b/ffmpeg/transcoder.c @@ -335,6 +335,19 @@ int transcode(struct transcode_thread *h, av_frame_unref(dframe); ret = process_in(ictx, dframe, ipkt, &stream_index); if (ret == AVERROR_EOF) { + // if we're to loop, mark discontinuity and seek back to 0 + if (ictx->loop != 0) { + lpms_transcode_discontinuity(h); + ret = avformat_seek_file(ictx->ic, -1, INT64_MIN, 0, INT64_MAX, 0); + if (ret < 0) { + LPMS_WARN("loop failed"); + return ret; + } + if (ictx->loop > 0) { + ictx->loop--; + } + continue; + } // no more processing, go for flushes break; } diff --git a/ffmpeg/transcoder.h b/ffmpeg/transcoder.h index 8c1c4888b4..57f1d7e9f5 100755 --- a/ffmpeg/transcoder.h +++ b/ffmpeg/transcoder.h @@ -58,6 +58,8 @@ typedef struct { // concatenates multiple inputs into the same output int transmuxing; + // loops input n times. -1 for forever + int loop; } input_params; #define MAX_CLASSIFY_SIZE 10