博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
微软云平台媒体服务实践系列 2- 使用动态封装为iOS, Android , Windows 等多平台提供视频点播(VoD)方案...
阅读量:4880 次
发布时间:2019-06-11

本文共 8663 字,大约阅读时间需要 28 分钟。

文章  介绍了如何针对少数iOS, Android 客户端的场景,出于节约成本的目的使用媒体服务的静态封装实现视频点播方案。实际应用中,所支持的客户端越多,那么所获得的用户越多,客户端多种多样:PC端, Xbox, iOS, Android, Windows 等移动设备端,针对如此之大的客户端市场,能否搭建一套全面的点播方案呢?答案是肯定的,本文将基于微软云平台媒体服务介绍如何实现跨多移动客户端的视频点播方案。

微软的云平台为流媒体服务提供了多种选择,在使用流媒体服务为企业做流媒体方案时,首先需要确认要流媒体接收目标,如针对广大iOS, Android移动设备,由于它们都支持HLS 格式的流媒体,微软平台支持smooth streaming 格式,基于该认知,比较推荐的是使用,但是必须额外,方法是在Azure 门户,点击媒体服务,然后点击所使用的媒体服务,选择流式处理端点标签页,选择需要编辑的流媒体端点,然后再缩放标签页下设置,如下截图所示:

     

 使用制定支持Windows, iOS, Android 平台的视频点播方案的流程如下截图所示:原始媒体文件——>转码为MP4文件——>使用动态封装功能,按照客户端需求提供流媒体码流, 构造流媒体地址——>测试。

  

 此外我们还可以在编码过程中, 需要使用到相应的配置文件Thumbnail_Configuration.xml,内容如下:

<?xml version=”1.0″ encoding=”utf-8″?>

<Thumbnail Size=”100%,*” Type=”Jpeg” Filename=”{OriginalFilename}_{Size}_{ThumbnailTime}_{ThumbnailIndex}_{Date}_{Time}.{DefaultExtension}”>

    <Time Value=”10%” Step=”10%” Stop=”95%”/>

</Thumbnail>

 

整个代码流程可以参考如下:(使用流媒体服务.Net SDK,注意指定媒体服务的账号名字(accName)及key(accKey))

class Program

    {

        private static string accName = “[MediaService_accountName]”;

        private static string accKey = “[MediaService_accountKey]”;      

 

        private static readonly string _supportFiles =

            Path.GetFullPath(@”../..\..\..\..\”);

 

        // Paths to support files (within the above base path).

        // provide paths to your own media files below to run.

        private static readonly string singleInputFilePath =

            Path.GetFullPath(_supportFiles + @”\azure.wmv”);

        private static readonly string outputPath = _supportFiles;

        private static CloudMediaContext context;

        private static readonly string configFilePath = Path.GetFullPath(_supportFiles + @”\Thumbnail_Configuration.xml”);

        static void Main(string[] args)

        {

            context = new CloudMediaContext(accName, accKey);

 

            string inputAssetId = CreateAssetAndUploadFile(context);

 

            //thumbnail

            IJob jobThumb = ThumbnailMaker(context, inputAssetId);

            string thumbnailUri = GetThumbnailUrl(context, jobThumb.OutputMediaAssets[0]);

 

            //encode to MP4

            IJob job = EncodeToMp4(context, inputAssetId);

            IAsset mp4Output = job.OutputMediaAssets.FirstOrDefault();                     

           

            //Dynamic Packaging

            var mp4Asset = job.OutputMediaAssets.FirstOrDefault();

            string mp4Url = GetDynamicStreamingUrl(context, mp4Asset.Id, LocatorType.Sas);

            string smoothStreamingUrl = GetDynamicStreamingUrl(context, mp4Asset.Id, LocatorType.OnDemandOrigin);

 

            string hlsStreamingUrl = smoothStreamingUrl + “(format=m3u8-aapl)”;

            string mpegdashStreamingUrl = smoothStreamingUrl + “(format=mpd-time-csf)”;

 

            //Output

            string content = “\n Thumbnail Url:    \n” + thumbnailUri

                              +”\n Mp4 Url:    \n” + mp4Url

                              + “\n Dynamic Packaging Smooth Url: \n” + smoothStreamingUrl

                              +”\n Dynamic Packaging HLS Url:    \n” + hlsStreamingUrl

                              +”\n Dynamic Packaging MPEG DASH Url:    \n” + mpegdashStreamingUrl;

 

            Console.WriteLine(“\n Thumbnail Url:    \n” + thumbnailUri);

            Console.WriteLine(“\n Mp4 Url:    \n” + mp4Url);

            Console.WriteLine(“\n Smooth Url: \n” + smoothStreamingUrl);

            Console.WriteLine(“\n HLS Url:    \n” + hlsStreamingUrl);

            Console.WriteLine(“\n MPEG DASH Url:    \n” + mpegdashStreamingUrl);

 

            string outFilePath = Path.GetFullPath(outputPath + @”\” + “StreamingUrl.txt”);

            WriteToFile(outFilePath, content);

            Console.ReadKey();

            Console.ReadKey();

        }

 

        private static string CreateAssetAndUploadFile(CloudMediaContext context)

        {

            var assetName = Path.GetFileNameWithoutExtension(singleInputFilePath);

            var inputAsset = context.Assets.Create(assetName, AssetCreationOptions.None);

            var assetFile = inputAsset.AssetFiles.Create(Path.GetFileName(singleInputFilePath));

            assetFile.UploadProgressChanged += new EventHandler<UploadProgressChangedEventArgs>(assetFile_UploadProgressChanged);          

            assetFile.Upload(singleInputFilePath);

            return inputAsset.Id;

        }

 

        static void assetFile_UploadProgressChanged(object sender, UploadProgressChangedEventArgs e)

        {

            Console.WriteLine(string.Format(“{0}   Progress: {1:0}   Time: {2}”, ((IAssetFile)sender).Name, e.Progress, DateTime.UtcNow.ToString(@”yyyy_M_d__hh_mm_ss”)));

        }

 

        private static IJob EncodeToMp4(CloudMediaContext context, string inputAssetId)

        {

            var inputAsset = context.Assets.Where(a => a.Id == inputAssetId).FirstOrDefault();

            if (inputAsset == null)

                throw new ArgumentException(“Could not find assetId: ” + inputAssetId);         

            var encodingPreset = “H264 Adaptive Bitrate MP4 Set 720p”;          

            IJob job = context.Jobs.Create(“.Net Encoding  ” + inputAsset.Name + ” to MP4 job”);

            IMediaProcessor latestWameMediaProcessor = (from p in context.MediaProcessors where p.Name == “Windows Azure Media Encoder” select p).ToList()

                                                                         .OrderBy(wame => new Version(wame.Version)).LastOrDefault();

        

            ITask encodeTask = job.Tasks.AddNew(“.Net Encoding to Mp4 Task “, latestWameMediaProcessor, encodingPreset, TaskOptions.None);

            encodeTask.InputAssets.Add(inputAsset);

            encodeTask.OutputAssets.AddNew(inputAsset.Name + ” as ” + ” mp4 output asset”, AssetCreationOptions.None);

            job.StateChanged += new EventHandler<JobStateChangedEventArgs>(JobStateChanged);

            job.Submit();

            job.GetExecutionProgressTask(CancellationToken.None).Wait();

            return job;

        }

 

 

       

        static void JobStateChanged(object sender, JobStateChangedEventArgs e)

        {

            Console.WriteLine(string.Format(“{0}\n  State: {1}\n  Time: {2}\n\n”,

                                           ((IJob)sender).Name, e.CurrentState, DateTime.UtcNow.ToString(@”yyyy_M_d__hh_mm_ss”)));

        }

        static void WriteToFile(string outFilePath, string fileContent)

        {

            StreamWriter sr = File.CreateText(outFilePath);

            sr.Write(fileContent);

            sr.Close();

        }

 

 

        private static string GetDynamicStreamingUrl(CloudMediaContext context, string outputAssetId, LocatorType type)

        {

            var daysForWhichStreamingUrlIsActive = 365;

            var outputAsset = context.Assets.Where(a => a.Id == outputAssetId).FirstOrDefault();

            var accessPolicy = context.AccessPolicies.Create(outputAsset.Name,

                                                             TimeSpan.FromDays(daysForWhichStreamingUrlIsActive),

                                                             AccessPermissions.Read | AccessPermissions.List);

 

            var assetFiles = outputAsset.AssetFiles.ToList();

            if (type == LocatorType.OnDemandOrigin)

            {

                var assetFile = assetFiles.Where(f => f.Name.ToLower().EndsWith(“.ism”)).FirstOrDefault();

                if (assetFile != null)

                {

                    var locator = context.Locators.CreateLocator(LocatorType.OnDemandOrigin, outputAsset, accessPolicy);

                    Uri smoothUri = new Uri(locator.Path + assetFile.Name + “/manifest”);

                    return smoothUri.ToString();

                }

            }

            if (type == LocatorType.Sas)

            {

                var mp4Files = assetFiles.Where(f => f.Name.ToLower().EndsWith(“.mp4″)).ToList();

                var assetFile = mp4Files.OrderBy(f => f.ContentFileSize).LastOrDefault(); //Get Largest File

                if (assetFile != null)

                {

                    var locator = context.Locators.CreateLocator(LocatorType.Sas, outputAsset, accessPolicy);

                    var mp4Uri = new UriBuilder(locator.Path);

                    mp4Uri.Path += “/” + assetFile.Name;

                    return mp4Uri.ToString();

                }

            }

            return string.Empty;

        }

                    

    

        private static IJob ThumbnailMaker(CloudMediaContext context, string inputAssetId)

        {

 

            var inputAsset = context.Assets.Where(a => a.Id == inputAssetId).FirstOrDefault();

            if (inputAsset == null)

                throw new ArgumentException(“Could not find assetId: ” + inputAssetId);

         

            IMediaProcessor latestWameMediaProcessor = (from p in context.MediaProcessors where p.Name == “Windows Azure Media Encoder” select p).ToList()

                                                                         .OrderBy(wame => new Version(wame.Version)).LastOrDefault();

 

            //thumbnail

            //Get thumbnail configuration from a XML file

            var ThumbnailConfig = File.ReadAllText(configFilePath);

            // Create a job

            IJob jobThumbnail = context.Jobs.Create(“Thumbnail job Thumbnail Making ” + inputAsset.Name);

            //Create a task

            ITask thumbnailTask = jobThumbnail.Tasks.AddNew(“Thumbnail task”,

                latestWameMediaProcessor,             

                ThumbnailConfig,

                TaskOptions.None);

 

            thumbnailTask.InputAssets.Add(inputAsset);

            thumbnailTask.OutputAssets.AddNew(inputAsset.Name + ” as Thumbnail job”, AssetCreationOptions.None);

            jobThumbnail.StateChanged += new EventHandler<JobStateChangedEventArgs>(JobStateChanged);

            jobThumbnail.Submit();

            jobThumbnail.GetExecutionProgressTask(CancellationToken.None).Wait();

            return jobThumbnail;

        }

        private static string GetThumbnailUrl(CloudMediaContext context, IAsset outputAsset)

        {           

            var output = outputAsset;

            var accessPolicy = context.AccessPolicies.Create(“Read Policy”, TimeSpan.FromDays(10), AccessPermissions.Read);         

            var locator = context.Locators.CreateSasLocator(output, accessPolicy);

            var primaryFile = (from a in output.AssetFiles

                               where a.IsPrimary == true

                               select a).FirstOrDefault();

            return locator.BaseUri + ‘/’ + primaryFile.Name + locator.ContentAccessComponent;

        }

    }

最终我们可以获得编码后的视频缩略图地址、MP4 文件地址(可以直接用于网页,使用Video tag)、Smooth Streaming, HLS, MPEG-DASH地址:

Thumbnail URL: 

MP4 URL: 

Smooth Streaming URL:   

HLS:

MPEG-DASH: 

 

自适应流媒体的最大的特征是根据客户端的网络带宽情况自适应地选择对应码流媒体内容进行传输,保证流畅的视频播放体验,因此需要特殊的客户端播放器。对于这3种常用的流媒体格式,可以使用如下播放器进行测试:

Smooth Streaming player: 

HLS: JW player: 

MPEG-DASH player: 

 微软官方DEMO测试地址:http://ampdemo.azureedge.net/

https://blogs.msdn.microsoft.com/lj/2015/02/09/1-ios-android-23454/

 

转载于:https://www.cnblogs.com/zangdalei/p/5304028.html

你可能感兴趣的文章
php开启openssl的方法,openssl安装
查看>>
集合类转化成数组
查看>>
什么是Java 虚拟机?为什么Java 被称作是"平台无关的编程语言"?
查看>>
better-scroll和swiper使用中的坑
查看>>
css之字体的引用
查看>>
oo第一单元博客
查看>>
实验报告三
查看>>
基础搜索
查看>>
vs2008 C# 怎么调试C++ dll[转]
查看>>
PHP的魔术方法
查看>>
警惕麦咖啡的"缓冲区溢出保护"引起的ASP.NET 中 System.OutOfMemoryException 的错误...
查看>>
optimizer_dynamic_sampling
查看>>
HTML(WEB)开发day05
查看>>
5月16日(优化链串BF算法、
查看>>
php学习
查看>>
第四节 选择结构和循环结构
查看>>
新的Android应用 记账理财助手 登陆国内各大市场啦。
查看>>
【转】c++中placement new操作符
查看>>
收缩日志
查看>>
tmux
查看>>