Skip to content

Commit

Permalink
Finalizing new Seek also for network (slow) streams
Browse files Browse the repository at this point in the history
Former-commit-id: 2b24b2c
  • Loading branch information
SuRGeoNix committed Mar 7, 2021
1 parent 953348e commit f5ecc21
Show file tree
Hide file tree
Showing 7 changed files with 207 additions and 173 deletions.
19 changes: 6 additions & 13 deletions Flyleaf/Controls/FlyleafPlayer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -481,10 +481,10 @@ private void Player_StatusChanged(object source, StatusChangedArgs e)
{
if (InvokeRequired) { BeginInvoke(new Action(() => Player_StatusChanged(source, e))); return; }

if (e.status == MediaRouter.Status.PLAYING)
{ tblBar.btnPlay.BackgroundImage = Properties.Resources.Pause; tblBar.btnPlay.Text = " "; playingStartedSec = (int)(player.CurTime / 10000000) + 1; timerLoop = 0; }
if (e.status == MediaRouter.Status.PLAYING)
{ tblBar.btnPlay.BackgroundImage = Properties.Resources.Pause; tblBar.btnPlay.Text = " "; playingStartedSec = (int)(player.CurTime / 10000000) + 1; timerLoop = 0; }
else
{ tblBar.btnPlay.BackgroundImage = Properties.Resources.Play; tblBar.btnPlay.Text = ""; }
{ tblBar.btnPlay.BackgroundImage = Properties.Resources.Play; tblBar.btnPlay.Text = ""; }
}
private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
Expand Down Expand Up @@ -613,6 +613,8 @@ public void Open(string url)
{
curHistoryEntry = null;
player.Open(url);
tblBar.seekBar.Maximum = 1;
tblBar.seekBar.SetValue(1);
}
public void MediaFilesReceived(List<string> mediaFiles, List<long> mediaFilesSizes)
{
Expand Down Expand Up @@ -1209,16 +1211,7 @@ private void FlyLeaf_KeyPress (object sender, KeyPressEventArgs e)
else if (lvSubs.Visible) FixLvSubs(false);
else if (isFullScreen) FullScreenToggle();
}
//{
// if (picHelp.Visible)
// picHelp.Visible = false;

// else
// MediaFilesToggle();
//}

//lastUserActionTicks = DateTime.UtcNow.Ticks;
}
}

private void FlyLeaf_MouseMove (object sender, MouseEventArgs e)
{
Expand Down
1 change: 1 addition & 0 deletions Flyleaf/MediaFramework/Decoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,7 @@ public void Decode()
{
status = Status.END;
Log("EOF");
if (type == Type.Video) { Log("EOF All"); decCtx.status = Status.END; }
break;
}

Expand Down
2 changes: 1 addition & 1 deletion Flyleaf/MediaFramework/DecoderContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ public long GetVideoFrame()
{
MediaFrame mFrame = new MediaFrame();
mFrame.pts = frame->best_effort_timestamp == AV_NOPTS_VALUE ? frame->pts : frame->best_effort_timestamp;
mFrame.timestamp = (long)((mFrame.pts * vDecoder.info.Timebase) + opt.audio.LatencyTicks);
mFrame.timestamp = ((long)(mFrame.pts * vDecoder.info.Timebase) - demuxer.streams[vDecoder.st->index].StartTime) + opt.audio.LatencyTicks;

if (mFrame.pts == AV_NOPTS_VALUE)
{
Expand Down
44 changes: 24 additions & 20 deletions Flyleaf/MediaFramework/Demuxer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public unsafe class Demuxer
GCHandle decCtxHandle = (GCHandle) ((IntPtr) opaque);
DecoderContext decCtx = (DecoderContext) decCtxHandle.Target;

//Console.WriteLine($"** R | { decCtx.demuxer.fmtCtx->pb->pos} - {decCtx.demuxer.ioStream.Position}");
//Console.WriteLine($"** R | { decCtx.demuxer.fmtCtx->pb->pos} - {decCtx.demuxer.ioStream.Position} | {decCtx.demuxer.fmtCtx->io_repositioned}");

// During seek, it will destroy the sesion on Matroska (requires reopen the format input)
if (decCtx.interrupt == 1) { Console.WriteLine("[Stream] Interrupt 1"); return AVERROR_EXIT; }
Expand Down Expand Up @@ -173,15 +173,25 @@ public int Open(string url, bool doAudio = true, bool doSubs = true, Stream stre
* [tls @ 0e691280] The specified session has been invalidated for some reason.
* [DECTX AVMEDIA_TYPE_AUDIO] AVMEDIA_TYPE_UNKNOWN - Error[-0005], Msg: I/O error
*/

//av_dict_set(&opt, "rtsp_transport", "tcp", 0);

//av_dict_set_int(&opt, "rw_timeout", 10 * 1000 * 1000, 0);
//av_dict_set_int(&opt, "timeout", 10 * 1000 * 1000, 0);

av_dict_set_int(&opt, "stimeout", 10 * 1000 * 1000, 0); // RTSP microseconds timeout

av_dict_set_int(&opt, "reconnect" , 1, 0); // auto reconnect after disconnect before EOF
av_dict_set_int(&opt, "reconnect_streamed" , 1, 0); // auto reconnect streamed / non seekable streams
av_dict_set_int(&opt, "reconnect_delay_max" , 10, 0); // max reconnect delay in seconds after which to give up
//av_dict_set_int(&opt, "reconnect_at_eof", 1, 0); // auto reconnect at EOF | Maybe will use this for another similar issues? | will not stop the decoders (no EOF)
av_dict_set_int(&opt, "stimeout", 10 * 1000 * 1000, 0); // RTSP microseconds timeout



fmtCtx = avformat_alloc_context();
fmtCtx->interrupt_callback.callback = interruptClbk;
fmtCtx->interrupt_callback.opaque = (void*)decCtx.decCtxPtr;
fmtCtx->flags |= AVFMT_FLAG_DISCARD_CORRUPT;

if (stream != null)
{
Expand Down Expand Up @@ -259,6 +269,7 @@ public int Open(string url, bool doAudio = true, bool doSubs = true, Stream stre
status = Status.READY;

pkt = av_packet_alloc();

return 0;
}
public void Close()
Expand Down Expand Up @@ -312,22 +323,22 @@ public void Pause()
public int Seek(long ms, bool foreward = false)
{
if (status == Status.NOTSET) return -1;
if (status == Status.END) status = Status.READY; //Open(url, ...); // Usefull for HTTP
if (status == Status.END) { if (fmtCtx->pb == null) Open(url, decCtx.opt.audio.Enabled, false); else status = Status.READY; } //Open(url, ...); // Usefull for HTTP

int ret;
long seekTs = CalcSeekTimestamp(ms);
Log("[SEEK] " + Utils.TicksToTime(seekTs * 10));
Log("[SEEK] " + Utils.TicksToTime(seekTs));

if (foreward)
ret = av_seek_frame(fmtCtx, -1, seekTs, AVSEEK_FLAG_FRAME);
ret = av_seek_frame(fmtCtx, -1, seekTs / 10, AVSEEK_FLAG_FRAME);
else
ret = av_seek_frame(fmtCtx, -1, seekTs, AVSEEK_FLAG_BACKWARD);
ret = av_seek_frame(fmtCtx, -1, seekTs / 10, AVSEEK_FLAG_BACKWARD);

if (ret < 0)
{
Log($"[SEEK] [ERROR-1] {Utils.ErrorCodeToMsg(ret)} ({ret})");
ret = av_seek_frame(fmtCtx, -1, seekTs, AVSEEK_FLAG_ANY);
//if (seek2any) avformat_seek_file(fmtCtx, -1, Int64.MinValue, seekTs, seekTs, AVSEEK_FLAG_ANY); // Same as av_seek_frame ?
ret = av_seek_frame(fmtCtx, -1, seekTs / 10, AVSEEK_FLAG_ANY);
//if (seek2any) avformat_seek_file(fmtCtx, -1, Int64.MinValue, seekTs / 10, seekTs / 10, AVSEEK_FLAG_ANY); // Same as av_seek_frame ?
if (ret < 0) Log($"[SEEK] [ERROR-2] {Utils.ErrorCodeToMsg(ret)} ({ret})");
}

Expand All @@ -337,20 +348,13 @@ public long CalcSeekTimestamp(long ms)
{
long ticks = ((ms * 10000) + streams[decoder.st->index].StartTime) - decCtx.opt.audio.LatencyTicks;

switch (type)
{
case Type.Video:
return ticks / 10;
if (type == Type.Audio) ticks -= decCtx.opt.audio.DelayTicks;
if (type == Type.Subs ) ticks -= decCtx.opt.subs. DelayTicks;

case Type.Audio:
return (ticks - decCtx.opt.audio.DelayTicks) / 10;
if (ticks < streams[decoder.st->index].StartTime) ticks = streams[decoder.st->index].StartTime;// + (1 * (long)10000);
else if (ticks > streams[decoder.st->index].StartTime + streams[decoder.st->index].DurationTicks) ticks = streams[decoder.st->index].StartTime + streams[decoder.st->index].DurationTicks;

case Type.Subs:
return (ticks - decCtx.opt.subs.DelayTicks) / 10;

default:
return 0;
}
return ticks;
}
public void ReSync(long ms = -1)
{
Expand Down
15 changes: 8 additions & 7 deletions Flyleaf/MediaFramework/StreamInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public unsafe class StreamInfo
// All
public AVMediaType Type { get; private set; }
public AVCodecID CodecID { get; private set; }
public string CodecIDStr { get { return CodecID.ToString().Replace("AV_CODEC_ID_", ""); } }
public string CodecName { get; private set; } //{ get { return CodecID.ToString().Replace("AV_CODEC_ID_", ""); } }
public int StreamIndex { get; private set; }
public double Timebase { get; private set; }

Expand Down Expand Up @@ -47,6 +47,7 @@ public static StreamInfo Get(AVStream* st)

si.Type = st->codecpar->codec_type;
si.CodecID = st->codecpar->codec_id;
si.CodecName = avcodec_get_name(st->codecpar->codec_id);
si.StreamIndex = st->index;
si.Timebase = av_q2d(st->time_base) * 10000.0 * 1000.0;
si.DurationTicks = (long)(st->duration * si.Timebase);
Expand Down Expand Up @@ -100,23 +101,23 @@ public string GetDump()
string dump = "";

if (Type == AVMEDIA_TYPE_AUDIO)
dump = $"[#{StreamIndex} Audio] {CodecIDStr} {SampleFormatStr}@{Bits} {SampleRate/1000}KHz {ChannelLayoutStr} | {AudioBitRate}";
dump = $"[#{StreamIndex} Audio] {CodecName} {SampleFormatStr}@{Bits} {SampleRate/1000}KHz {ChannelLayoutStr} | {AudioBitRate}";
else if (Type == AVMEDIA_TYPE_VIDEO)
dump = $"[#{StreamIndex} Video] {CodecIDStr} {PixelFormatStr} {Width}x{Height} @ {FPS.ToString("#.###")} ({AspectRatio.den}/{AspectRatio.num}) | {VideoBitRate}";
dump = $"[#{StreamIndex} Video] {CodecName} {PixelFormatStr} {Width}x{Height} @ {FPS.ToString("#.###")} ({AspectRatio.den}/{AspectRatio.num}) | {VideoBitRate}";
else if (Type == AVMEDIA_TYPE_SUBTITLE)
dump = $"[#{StreamIndex} Subs] {CodecIDStr} " + (Metadata.ContainsKey("language") ? Metadata["language"] : (Metadata.ContainsKey("lang") ? Metadata["language"] : ""));
dump = $"[#{StreamIndex} Subs] {CodecName} " + (Metadata.ContainsKey("language") ? Metadata["language"] : (Metadata.ContainsKey("lang") ? Metadata["language"] : ""));

return dump;
}

public static void Dump(StreamInfo si)
{
if (si.Type == AVMEDIA_TYPE_AUDIO)
Console.WriteLine($"[#{si.StreamIndex} Audio] {si.CodecIDStr} {si.SampleFormatStr}@{si.Bits} {si.SampleRate/1000}KHz {si.ChannelLayoutStr} | {si.AudioBitRate}");
Console.WriteLine($"[#{si.StreamIndex} Audio] {si.CodecName} {si.SampleFormatStr}@{si.Bits} {si.SampleRate/1000}KHz {si.ChannelLayoutStr} | {si.AudioBitRate}");
else if (si.Type == AVMEDIA_TYPE_VIDEO)
Console.WriteLine($"[#{si.StreamIndex} Video] {si.CodecIDStr} {si.PixelFormatStr} {si.Width}x{si.Height} @ {si.FPS.ToString("#.###")} ({si.AspectRatio.den}/{si.AspectRatio.num}) | {si.VideoBitRate}");
Console.WriteLine($"[#{si.StreamIndex} Video] {si.CodecName} {si.PixelFormatStr} {si.Width}x{si.Height} @ {si.FPS.ToString("#.###")} ({si.AspectRatio.den}/{si.AspectRatio.num}) | {si.VideoBitRate}");
else if (si.Type == AVMEDIA_TYPE_SUBTITLE)
Console.WriteLine($"[#{si.StreamIndex} Subs] {si.CodecIDStr} " + (si.Metadata.ContainsKey("language") ? si.Metadata["language"] : (si.Metadata.ContainsKey("lang") ? si.Metadata["language"] : "")));
Console.WriteLine($"[#{si.StreamIndex} Subs] {si.CodecName} " + (si.Metadata.ContainsKey("language") ? si.Metadata["language"] : (si.Metadata.ContainsKey("lang") ? si.Metadata["language"] : "")));
}

public static void Fill(Demuxer demuxer)
Expand Down
Loading

0 comments on commit f5ecc21

Please sign in to comment.