From 195f309c915c376aba13b191c1dd989c14279bf9 Mon Sep 17 00:00:00 2001 From: Jens Georg Date: Fri, 22 Jul 2011 14:12:18 +0200 Subject: [PATCH] core: Refactor video transcoders https://bugzilla.gnome.org/show_bug.cgi?id=661891 --- src/rygel/Makefile.am | 1 + src/rygel/rygel-avc-transcoder.vala | 88 +++++++--------------------- src/rygel/rygel-mp2ts-transcoder.vala | 80 ++++++++++---------------- src/rygel/rygel-video-transcoder.vala | 104 ++++++++++++++++++++++++++++++++++ src/rygel/rygel-wmv-transcoder.vala | 69 +++------------------- 5 files changed, 161 insertions(+), 181 deletions(-) create mode 100644 src/rygel/rygel-video-transcoder.vala diff --git a/src/rygel/Makefile.am b/src/rygel/Makefile.am index 05872f7..2518aa3 100644 --- a/src/rygel/Makefile.am +++ b/src/rygel/Makefile.am @@ -96,6 +96,7 @@ VAPI_SOURCE_FILES = \ rygel-search-criteria-parser.vala \ rygel-transcoder.vala \ rygel-audio-transcoder.vala \ + rygel-video-transcoder.vala \ rygel-mp2ts-transcoder.vala \ rygel-mp3-transcoder.vala \ rygel-l16-transcoder.vala \ diff --git a/src/rygel/rygel-avc-transcoder.vala b/src/rygel/rygel-avc-transcoder.vala index 0211a90..17a325f 100644 --- a/src/rygel/rygel-avc-transcoder.vala +++ b/src/rygel/rygel-avc-transcoder.vala @@ -22,79 +22,29 @@ using Gst; using GUPnP; -internal class Rygel.AVCTranscoder : Rygel.Transcoder { - private const int BITRATE = 1200000; +/** + * Transcoder for H.264 in MP4 conforming to DLNA profile + * AVC_MP4_BL_CIF15_AAC_520 (15 fps, CIF resolution) + */ +internal class Rygel.AVCTranscoder : Rygel.VideoTranscoder { private const int VIDEO_BITRATE = 1200; private const int AUDIO_BITRATE = 64; + private const string CONTAINER = "video/quicktime,variant=iso"; + private const string AUDIO_CAPS = "audio/mpeg,mpegversion=4"; + private const string VIDEO_CAPS = + "video/x-h264,stream-format=avc,framerate=(fraction)15/1"; - private const string RESTRICTIONS = "framerate=(fraction)15/1," + - "width=352,height=288"; + private const string RESTRICTIONS = + "framerate=(fraction)15/1,width=352,height=288"; public AVCTranscoder () { - base ("video/mp4", "AVC_MP4_BL_CIF15_AAC_520", VideoItem.UPNP_CLASS); - } - - public override DIDLLiteResource? add_resource (DIDLLiteItem didl_item, - MediaItem item, - TranscodeManager manager) - throws Error { - var resource = base.add_resource (didl_item, item, manager); - if (resource == null) { - return null; - } - - var video_item = item as VideoItem; - - resource.width = video_item.width; - resource.height = video_item.height; - resource.bitrate = (VIDEO_BITRATE + AUDIO_BITRATE) * 1000 / 8; - - return resource; - } - - public override uint get_distance (MediaItem item) { - if (!(item is VideoItem)) { - return uint.MAX; - } - - var video_item = item as VideoItem; - var distance = uint.MIN; - - if (video_item.bitrate > 0) { - distance += (video_item.bitrate - BITRATE).abs (); - } - - return distance; - } - - protected override EncodingProfile get_encoding_profile () { - var container_format = Caps.from_string ("video/quicktime,variant=iso"); - - var video_format = Caps.from_string ("video/x-h264," + - "stream-format=avc," + - "framerate=(fraction)15/1"); - var audio_format = Caps.from_string ("audio/mpeg,mpegversion=4"); - - var enc_container_profile = new EncodingContainerProfile("container", - null, - container_format, - null); - - var video_restriction = Caps.from_string (RESTRICTIONS); - - var enc_video_profile = new EncodingVideoProfile (video_format, - null, - video_restriction, - 1); - var enc_audio_profile = new EncodingAudioProfile (audio_format, - null, - null, - 1); - - // FIXME: We should use the preset to set bitrate - enc_container_profile.add_profile (enc_video_profile); - enc_container_profile.add_profile (enc_audio_profile); - - return enc_container_profile; + base ("video/mp4", + "AVC_MP4_BL_CIF15_AAC_520", + AUDIO_BITRATE, + VIDEO_BITRATE, + CONTAINER, + AUDIO_CAPS, + VIDEO_CAPS, + RESTRICTIONS); } } diff --git a/src/rygel/rygel-mp2ts-transcoder.vala b/src/rygel/rygel-mp2ts-transcoder.vala index 93bc793..677f651 100644 --- a/src/rygel/rygel-mp2ts-transcoder.vala +++ b/src/rygel/rygel-mp2ts-transcoder.vala @@ -22,7 +22,6 @@ */ using Gst; using GUPnP; -using Gee; internal enum Rygel.MP2TSProfile { SD = 0, @@ -32,7 +31,7 @@ internal enum Rygel.MP2TSProfile { /** * Transcoder for mpeg transport stream containing mpeg 2 video and mp2 audio. */ -internal class Rygel.MP2TSTranscoder : Rygel.Transcoder { +internal class Rygel.MP2TSTranscoder : Rygel.VideoTranscoder { private const int VIDEO_BITRATE = 3000; private const int AUDIO_BITRATE = 256; @@ -41,12 +40,32 @@ internal class Rygel.MP2TSTranscoder : Rygel.Transcoder { private const int[] HEIGHT = {576, 720}; private const int[] FRAME_RATE = {25, 30}; private const string[] PROFILES = {"MPEG_TS_SD_EU_ISO", "MPEG_TS_HD_NA_ISO"}; - private const int BITRATE = 3000000; + + private const string CONTAINER = + "video/mpegts,systemstream=true,paketsize=188"; + + private const string AUDIO_FORMAT = + "audio/mpeg,mpegversion=1,layer=2"; + + private const string BASE_VIDEO_FORMAT = + "video/mpeg,mpegversion=2,systemstream=false,framerate=(fraction)%d/1"; + + private const string RESTRICTION_TEMPLATE = + "video/x-raw-yuv,framerate=(fraction)%d/1,width=%d,height=%d"; private MP2TSProfile profile; public MP2TSTranscoder (MP2TSProfile profile) { - base ("video/mpeg", PROFILES[profile], VideoItem.UPNP_CLASS); + base ("video/mpeg", + PROFILES[profile], + AUDIO_BITRATE, + VIDEO_BITRATE, + CONTAINER, + AUDIO_FORMAT, + BASE_VIDEO_FORMAT.printf (FRAME_RATE[profile]), + RESTRICTION_TEMPLATE.printf (FRAME_RATE[profile], + WIDTH[profile], + HEIGHT[profile])); this.profile = profile; } @@ -56,11 +75,12 @@ internal class Rygel.MP2TSTranscoder : Rygel.Transcoder { TranscodeManager manager) throws Error { var resource = base.add_resource (didl_item, item, manager); - if (resource == null) + if (resource == null) { return null; + } - resource.width = WIDTH[profile]; - resource.height = HEIGHT[profile]; + resource.width = WIDTH[this.profile]; + resource.height = HEIGHT[this.profile]; resource.bitrate = (VIDEO_BITRATE + AUDIO_BITRATE) * 1000 / 8; return resource; @@ -72,10 +92,10 @@ internal class Rygel.MP2TSTranscoder : Rygel.Transcoder { } var video_item = item as VideoItem; - var distance = uint.MIN; + var distance = base.get_distance (item); if (video_item.bitrate > 0) { - distance += (video_item.bitrate - BITRATE).abs (); + distance += (video_item.bitrate - VIDEO_BITRATE).abs (); } if (video_item.width > 0) { @@ -88,46 +108,4 @@ internal class Rygel.MP2TSTranscoder : Rygel.Transcoder { return distance; } - - protected override EncodingProfile get_encoding_profile () { - var cont_format = Caps.from_string ("video/mpegts," + - "systemstream=true," + - "packetsize=188"); - var framerate = "framerate=(fraction)%d/1".printf - (FRAME_RATE[this.profile]); - - var video_format = Caps.from_string ("video/mpeg," + - "mpegversion=2," + - "systemstream=false," + - framerate); - var restriction = "video/x-raw-yuv," + - framerate + "," + - "width=%d,".printf (WIDTH[this.profile]) + - "height=%d".printf (HEIGHT[this.profile]); - - var video_restriction = Caps.from_string (restriction); - - var audio_format = Caps.from_string ("audio/mpeg," + - "mpegversion=1," + - "layer=2"); - - var enc_container_profile = new EncodingContainerProfile ("container", - null, - cont_format, - null); - var enc_video_profile = new EncodingVideoProfile (video_format, - null, - video_restriction, - 1); - var enc_audio_profile = new EncodingAudioProfile (audio_format, - null, - null, - 1); - - // FIXME: We should use the preset to set bitrate - enc_container_profile.add_profile (enc_video_profile); - enc_container_profile.add_profile (enc_audio_profile); - - return enc_container_profile; - } } diff --git a/src/rygel/rygel-video-transcoder.vala b/src/rygel/rygel-video-transcoder.vala new file mode 100644 index 0000000..0b33bab --- /dev/null +++ b/src/rygel/rygel-video-transcoder.vala @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2011 Nokia Corporation. + * + * Author: Jens Georg + * + * This file is part of Rygel. + * + * Rygel is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Rygel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +using Gst; +using GUPnP; + +/** + * Base class for all transcoders that handle video. + */ +internal class Rygel.VideoTranscoder : Rygel.AudioTranscoder { + private int video_bitrate; + private Caps video_codec_format; + private Caps video_restrictions = null; + + public VideoTranscoder (string content_type, + string dlna_profile, + int audio_bitrate, + int video_bitrate, + string container_caps, + string audio_codec_caps, + string video_codec_caps, + string? restrictions = null) { + + base.with_class (content_type, + dlna_profile, + VideoItem.UPNP_CLASS, + audio_bitrate, + container_caps, + audio_codec_caps); + + this.video_bitrate = video_bitrate; + this.video_codec_format = Caps.from_string (video_codec_caps); + + if (restrictions != null) { + this.video_restrictions = Caps.from_string (restrictions); + } + } + + public override DIDLLiteResource? add_resource (DIDLLiteItem didl_item, + MediaItem item, + TranscodeManager manager) + throws Error { + var resource = base.add_resource (didl_item, item, manager); + if (resource == null) { + return null; + } + + var video_item = item as VideoItem; + + resource.width = video_item.width; + resource.height = video_item.height; + resource.bitrate = (this.video_bitrate + this.audio_bitrate) * 1000 / 8; + + return resource; + } + + public override uint get_distance (MediaItem item) { + if (!(item is VideoItem)) { + return uint.MAX; + } + + var video_item = item as VideoItem; + var distance = uint.MIN; + + if (video_item.bitrate > 0) { + distance += (video_item.bitrate - this.video_bitrate).abs (); + } + + return distance; + } + + protected override EncodingProfile get_encoding_profile () { + var enc_container_profile = base.get_encoding_profile () as + EncodingContainerProfile; + + var enc_video_profile = new EncodingVideoProfile + (this.video_codec_format, + null, + this.video_restrictions, + 1); + + enc_container_profile.add_profile (enc_video_profile); + + return enc_container_profile; + } +} diff --git a/src/rygel/rygel-wmv-transcoder.vala b/src/rygel/rygel-wmv-transcoder.vala index 9f93a99..a601ddc 100644 --- a/src/rygel/rygel-wmv-transcoder.vala +++ b/src/rygel/rygel-wmv-transcoder.vala @@ -22,70 +22,17 @@ using Gst; using GUPnP; -internal class Rygel.WMVTranscoder : Rygel.Transcoder { - private const int BITRATE = 1200000; +internal class Rygel.WMVTranscoder : Rygel.VideoTranscoder { private const int VIDEO_BITRATE = 1200; private const int AUDIO_BITRATE = 64; public WMVTranscoder () { - base ("video/x-ms-wmv", "WMVHIGH_FULL", VideoItem.UPNP_CLASS); - } - - public override DIDLLiteResource? add_resource (DIDLLiteItem didl_item, - MediaItem item, - TranscodeManager manager) - throws Error { - var resource = base.add_resource (didl_item, item, manager); - if (resource == null) - return null; - - var video_item = item as VideoItem; - - resource.width = video_item.width; - resource.height = video_item.height; - resource.bitrate = (VIDEO_BITRATE + AUDIO_BITRATE) * 1000 / 8; - - return resource; - } - - public override uint get_distance (MediaItem item) { - if (!(item is VideoItem)) { - return uint.MAX; - } - - var video_item = item as VideoItem; - var distance = uint.MIN; - - if (video_item.bitrate > 0) { - distance += (video_item.bitrate - BITRATE).abs (); - } - - return distance; - } - - protected override EncodingProfile get_encoding_profile () { - var container_format = Caps.from_string ("video/x-ms-asf,parsed=true"); - - var video_format = Caps.from_string ("video/x-wmv,wmvversion=1"); - var audio_format = Caps.from_string ("audio/x-wma,channels=2,wmaversion=1"); - - var enc_container_profile = new EncodingContainerProfile("container", - null, - container_format, - null); - var enc_video_profile = new EncodingVideoProfile (video_format, - null, - null, - 1); - var enc_audio_profile = new EncodingAudioProfile (audio_format, - null, - null, - 1); - - // FIXME: We should use the preset to set bitrate - enc_container_profile.add_profile (enc_video_profile); - enc_container_profile.add_profile (enc_audio_profile); - - return enc_container_profile; + base ("video/x-ms-wmv", + "WMVHIGH_FULL", + AUDIO_BITRATE, + VIDEO_BITRATE, + "video/x-ms-asf,parsed=true", + "audio/x-wma,channels=2,wmaversion=1", + "video/x-wmv,wmvversion=1"); } } -- 2.7.4