Browse Source

use more accurate BANDWIDTH value in multi-variant playlist (#2023)

pull/2025/head
Jason Dove 2 weeks ago committed by GitHub
parent
commit
6d152e4b4a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 1
      CHANGELOG.md
  2. 3
      ErsatzTV.Application/Channels/Mapper.cs
  3. 3
      ErsatzTV.Application/Channels/Queries/GetChannelResolution.cs
  4. 3
      ErsatzTV.Application/Channels/Queries/GetChannelResolutionAndBitrate.cs
  5. 12
      ErsatzTV.Application/Channels/Queries/GetChannelResolutionAndBitrateHandler.cs
  6. 3
      ErsatzTV.Application/Channels/ResolutionAndBitrateViewModel.cs
  7. 9
      ErsatzTV/Controllers/IptvController.cs

1
CHANGELOG.md

@ -38,6 +38,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -38,6 +38,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Fix playout detail table to only reload once when resetting a playout
- Fix date formatting in playout detail table on reload (will now respect browser's `Accept-Language` header)
- Use cache busting to avoid UI errors after upgrading the MudBlazor library
- Fix multi-variant playlist to report more accurate `BANDWIDTH` value based on ffmpeg profile
## [25.1.0] - 2025-01-10
### Added

3
ErsatzTV.Application/Channels/Mapper.cs

@ -39,6 +39,9 @@ internal static class Mapper @@ -39,6 +39,9 @@ internal static class Mapper
internal static ResolutionViewModel ProjectToViewModel(Resolution resolution) =>
new(resolution.Height, resolution.Width);
internal static ResolutionAndBitrateViewModel ProjectToViewModel(Resolution resolution, int bitrate) =>
new(resolution.Height, resolution.Width, bitrate);
private static string GetLogo(Channel channel) =>
Optional(channel.Artwork.FirstOrDefault(a => a.ArtworkKind == ArtworkKind.Logo))
.Match(a => a.Path, string.Empty);

3
ErsatzTV.Application/Channels/Queries/GetChannelResolution.cs

@ -1,3 +0,0 @@ @@ -1,3 +0,0 @@
namespace ErsatzTV.Application.Channels;
public record GetChannelResolution(string ChannelNumber) : IRequest<Option<ResolutionViewModel>>;

3
ErsatzTV.Application/Channels/Queries/GetChannelResolutionAndBitrate.cs

@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
namespace ErsatzTV.Application.Channels;
public record GetChannelResolutionAndBitrate(string ChannelNumber) : IRequest<Option<ResolutionAndBitrateViewModel>>;

12
ErsatzTV.Application/Channels/Queries/GetChannelResolutionHandler.cs → ErsatzTV.Application/Channels/Queries/GetChannelResolutionAndBitrateHandler.cs

@ -5,11 +5,11 @@ using Microsoft.EntityFrameworkCore; @@ -5,11 +5,11 @@ using Microsoft.EntityFrameworkCore;
namespace ErsatzTV.Application.Channels;
public class GetChannelResolutionHandler(IDbContextFactory<TvContext> dbContextFactory)
: IRequestHandler<GetChannelResolution, Option<ResolutionViewModel>>
public class GetChannelResolutionAndBitrateHandler(IDbContextFactory<TvContext> dbContextFactory)
: IRequestHandler<GetChannelResolutionAndBitrate, Option<ResolutionAndBitrateViewModel>>
{
public async Task<Option<ResolutionViewModel>> Handle(
GetChannelResolution request,
public async Task<Option<ResolutionAndBitrateViewModel>> Handle(
GetChannelResolutionAndBitrate request,
CancellationToken cancellationToken)
{
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
@ -20,6 +20,8 @@ public class GetChannelResolutionHandler(IDbContextFactory<TvContext> dbContextF @@ -20,6 +20,8 @@ public class GetChannelResolutionHandler(IDbContextFactory<TvContext> dbContextF
.ThenInclude(ff => ff.Resolution)
.SelectOneAsync(c => c.Number, c => c.Number == request.ChannelNumber);
return maybeChannel.Map(c => Mapper.ProjectToViewModel(c.FFmpegProfile.Resolution));
return maybeChannel.Map(c => Mapper.ProjectToViewModel(
c.FFmpegProfile.Resolution,
(int)((c.FFmpegProfile.VideoBitrate * 1000 + c.FFmpegProfile.AudioBitrate * 1000) * 1.2)));
}
}

3
ErsatzTV.Application/Channels/ResolutionAndBitrateViewModel.cs

@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
namespace ErsatzTV.Application.Channels;
public record ResolutionAndBitrateViewModel(int Height, int Width, int Bitrate);

9
ErsatzTV/Controllers/IptvController.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using System.Diagnostics;
using System.Globalization;
using System.Text;
using CliWrap;
using ErsatzTV.Application.Channels;
@ -301,16 +302,18 @@ public class IptvController : ControllerBase @@ -301,16 +302,18 @@ public class IptvController : ControllerBase
"Failed to return ffmpeg multi-variant playlist; falling back to generated playlist");
}
Option<ResolutionViewModel> maybeResolution = await _mediator.Send(new GetChannelResolution(channelNumber));
Option<ResolutionAndBitrateViewModel> maybeResolutionAndBitrate = await _mediator.Send(new GetChannelResolutionAndBitrate(channelNumber));
string resolution = string.Empty;
foreach (ResolutionViewModel res in maybeResolution)
string bitrate = "10000000";
foreach (ResolutionAndBitrateViewModel res in maybeResolutionAndBitrate)
{
resolution = $",RESOLUTION={res.Width}x{res.Height}";
bitrate = res.Bitrate.ToString(CultureInfo.InvariantCulture);
}
return $@"#EXTM3U
#EXT-X-VERSION:3
#EXT-X-STREAM-INF:BANDWIDTH=10000000{resolution}
#EXT-X-STREAM-INF:BANDWIDTH={bitrate}{resolution}
{variantPlaylist}";
}

Loading…
Cancel
Save