Browse Source

add start from beginning option to playback troubleshooting (#2182)

pull/2183/head
Jason Dove 1 year ago committed by GitHub
parent
commit
626af6876b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 8
      CHANGELOG.md
  2. 6
      ErsatzTV.Application/Troubleshooting/Commands/ArchiveTroubleshootingResults.cs
  3. 6
      ErsatzTV.Application/Troubleshooting/Commands/PrepareTroubleshootingPlayback.cs
  4. 13
      ErsatzTV.Application/Troubleshooting/Commands/PrepareTroubleshootingPlaybackHandler.cs
  5. 12
      ErsatzTV.Scanner.Tests/Core/FFmpeg/TranscodingTests.cs
  6. 8
      ErsatzTV/Controllers/Api/TroubleshootController.cs
  7. 14
      ErsatzTV/Pages/PlaybackTroubleshooting.razor

8
CHANGELOG.md

@ -107,11 +107,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -107,11 +107,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Remote Stream library items consist of YAML (`.yml`) files with the following fields
- `url`: the URL of the content that can be played directly by ffmpeg
- `script`: the process name and arguments for a command that will output content to stdout
- `duration`: when the content is "live" and does not have duration metadata, this must be provided to allow scheduling
- `is_live`: *required* property that indicates whether the remote stream contains live content
- When this is set to `true`, ETV cannot work ahead on transcoding this item, which is a necessary tradeoff for supporting live content
- When this is set to `false`, ETV will treat the stream as VOD and attempt to work ahead on transcoding like any other local item
- This *will* cause errors when the content is actually live, so it's important to configure this correctly
- When this is set to `true`, ETV cannot work ahead on transcoding this item, which is a necessary tradeoff for supporting live content
- When this is set to `false`, ETV will treat the stream as VOD and attempt to work ahead on transcoding like any other local item
- This *will* cause errors when the content is actually live, so it's important to configure this correctly
- `duration`: when the content is live and does not have duration metadata, this must be provided to allow scheduling
- The remote stream definition (YAML file) may provide either a `url` or a `script`
- If both are provided, `url` will be used

6
ErsatzTV.Application/Troubleshooting/Commands/ArchiveTroubleshootingResults.cs

@ -1,4 +1,8 @@ @@ -1,4 +1,8 @@
namespace ErsatzTV.Application.Troubleshooting;
public record ArchiveTroubleshootingResults(int MediaItemId, int FFmpegProfileId, int WatermarkId)
public record ArchiveTroubleshootingResults(
int MediaItemId,
int FFmpegProfileId,
int WatermarkId,
bool StartFromBeginning)
: IRequest<Option<string>>;

6
ErsatzTV.Application/Troubleshooting/Commands/PrepareTroubleshootingPlayback.cs

@ -3,5 +3,9 @@ using ErsatzTV.Core; @@ -3,5 +3,9 @@ using ErsatzTV.Core;
namespace ErsatzTV.Application.Troubleshooting;
public record PrepareTroubleshootingPlayback(int MediaItemId, int FFmpegProfileId, int WatermarkId)
public record PrepareTroubleshootingPlayback(
int MediaItemId,
int FFmpegProfileId,
int WatermarkId,
bool StartFromBeginning)
: IRequest<Either<BaseError, Command>>;

13
ErsatzTV.Application/Troubleshooting/Commands/PrepareTroubleshootingPlaybackHandler.cs

@ -96,6 +96,15 @@ public class PrepareTroubleshootingPlaybackHandler( @@ -96,6 +96,15 @@ public class PrepareTroubleshootingPlaybackHandler(
// we cannot burst live input
bool hlsRealtime = mediaItem is RemoteStream { IsLive: true };
TimeSpan inPoint = TimeSpan.Zero;
TimeSpan outPoint = duration;
if (!hlsRealtime && !request.StartFromBeginning)
{
inPoint = TimeSpan.FromSeconds(version.Duration.TotalSeconds / 2.0);
duration = TimeSpan.FromSeconds(duration.TotalSeconds / 2.0);
outPoint = inPoint + duration;
}
Command process = await ffmpegProcessService.ForPlayoutItem(
ffmpegPath,
ffprobePath,
@ -127,8 +136,8 @@ public class PrepareTroubleshootingPlaybackHandler( @@ -127,8 +136,8 @@ public class PrepareTroubleshootingPlaybackHandler(
Option<int>.None,
hlsRealtime,
FillerKind.None,
TimeSpan.Zero,
duration,
inPoint,
outPoint,
0,
None,
false,

12
ErsatzTV.Scanner.Tests/Core/FFmpeg/TranscodingTests.cs

@ -145,23 +145,23 @@ public class TranscodingTests @@ -145,23 +145,23 @@ public class TranscodingTests
public static InputFormat[] InputFormats =
[
// // // example format that requires colorspace filter
// new("libx264", "yuv420p", "tv", "smpte170m", "bt709", "smpte170m"),
new("libx264", "yuv420p", "tv", "smpte170m", "bt709", "smpte170m"),
// // //
// // // // example format that requires setparams filter
// new("libx264", "yuv420p", string.Empty, string.Empty, string.Empty, string.Empty),
new("libx264", "yuv420p", string.Empty, string.Empty, string.Empty, string.Empty),
// // //
// // // // new("libx264", "yuvj420p"),
// new("libx264", "yuv420p10le"),
new("libx264", "yuv420p10le"),
// // // // new("libx264", "yuv444p10le"),
// // //
// // // // new("mpeg1video", "yuv420p"),
// // // //
// new("mpeg2video", "yuv420p"),
new("mpeg2video", "yuv420p"),
// //
//new InputFormat("libx265", "yuv420p"),
new("libx265", "yuv420p10le")
new("libx265", "yuv420p10le"),
//
// new("mpeg4", "yuv420p"),
new("mpeg4", "yuv420p"),
//
// new("libvpx-vp9", "yuv420p"),
// new("libvpx-vp9", "yuv420p10le"),

8
ErsatzTV/Controllers/Api/TroubleshootController.cs

@ -26,10 +26,12 @@ public class TroubleshootController( @@ -26,10 +26,12 @@ public class TroubleshootController(
int ffmpegProfile,
[FromQuery]
int watermark,
[FromQuery]
bool startFromBeginning,
CancellationToken cancellationToken)
{
Either<BaseError, Command> result = await mediator.Send(
new PrepareTroubleshootingPlayback(mediaItem, ffmpegProfile, watermark),
new PrepareTroubleshootingPlayback(mediaItem, ffmpegProfile, watermark, startFromBeginning),
cancellationToken);
return await result.MatchAsync<IActionResult>(
@ -83,10 +85,12 @@ public class TroubleshootController( @@ -83,10 +85,12 @@ public class TroubleshootController(
int ffmpegProfile,
[FromQuery]
int watermark,
[FromQuery]
bool startFromBeginning,
CancellationToken cancellationToken)
{
Option<string> maybeArchivePath = await mediator.Send(
new ArchiveTroubleshootingResults(mediaItem, ffmpegProfile, watermark),
new ArchiveTroubleshootingResults(mediaItem, ffmpegProfile, watermark, startFromBeginning),
cancellationToken);
foreach (string archivePath in maybeArchivePath)

14
ErsatzTV/Pages/PlaybackTroubleshooting.razor

@ -64,6 +64,12 @@ @@ -64,6 +64,12 @@
}
</MudSelect>
</MudStack>
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
<div class="d-flex">
<MudText>Start From Beginning</MudText>
</div>
<MudCheckBox @bind-Value="_startFromBeginning" Dense="true" Disabled="@(string.Equals(_info?.Kind, "RemoteStream", StringComparison.OrdinalIgnoreCase))" />
</MudStack>
<MudText Typo="Typo.h5" Class="mt-10 mb-2">Preview</MudText>
<MudDivider Class="mb-6"/>
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
@ -72,7 +78,7 @@ @@ -72,7 +78,7 @@
Color="Color.Primary"
StartIcon="@Icons.Material.Filled.PlayCircle"
Disabled="@(Locker.IsTroubleshootingPlaybackLocked() || _mediaItemId is null)"
OnClick="PreviewChannel">
OnClick="@PreviewChannel">
Play
</MudButton>
</MudStack>
@ -105,6 +111,7 @@ @@ -105,6 +111,7 @@
private MediaItemInfo _info;
private int _ffmpegProfileId;
private int? _watermarkId;
private bool _startFromBeginning;
private bool _hasPlayed;
public void Dispose()
@ -136,7 +143,7 @@ @@ -136,7 +143,7 @@
{
var uri = new UriBuilder(NavigationManager.ToAbsoluteUri(NavigationManager.Uri));
uri.Path = uri.Path.Replace("/system/troubleshooting/playback", "/api/troubleshoot/playback.m3u8");
uri.Query = $"?mediaItem={_mediaItemId}&ffmpegProfile={_ffmpegProfileId}&watermark={_watermarkId ?? 0}";
uri.Query = $"?mediaItem={_mediaItemId}&ffmpegProfile={_ffmpegProfileId}&watermark={_watermarkId ?? 0}&startFromBeginning={_startFromBeginning}";
await JsRuntime.InvokeVoidAsync("previewChannel", uri.ToString());
await Task.Delay(TimeSpan.FromSeconds(1));
@ -155,6 +162,7 @@ @@ -155,6 +162,7 @@
foreach (MediaItemInfo info in maybeInfo.RightToSeq())
{
_info = info;
_startFromBeginning = string.Equals(info.Kind, "RemoteStream", StringComparison.OrdinalIgnoreCase);
}
if (maybeInfo.IsLeft)
@ -168,7 +176,7 @@ @@ -168,7 +176,7 @@
private async Task DownloadResults()
{
await JsRuntime.InvokeVoidAsync("window.open", $"api/troubleshoot/playback/archive?mediaItem={_mediaItemId ?? 0}&ffmpegProfile={_ffmpegProfileId}&watermark={_watermarkId ?? 0}");
await JsRuntime.InvokeVoidAsync("window.open", $"api/troubleshoot/playback/archive?mediaItem={_mediaItemId ?? 0}&ffmpegProfile={_ffmpegProfileId}&watermark={_watermarkId ?? 0}&startFromBeginning={_startFromBeginning}");
}
private void HandleTroubleshootingCompleted(PlaybackTroubleshootingCompletedNotification result)

Loading…
Cancel
Save