Mango开发实践,为什么看视频时声音和画面不同步

问:有电脑看电影时,音响一边是粤语,一边是国语,怎么办?

问:为什么看视频时声音和画面不同步?

  

图片 1

图片 2

 

不论这个视频的内容是什么,必定包含视频的内容和音频的内容,即便没有声音,但是音频轨道仍然存在。为了便于内容的传输和播放,我们需要封装与封装视频和音频的内容。

因为眼睛长在耳朵前面,所以先看见画面后听见声音,小学一年级老师都讲过这个科学道理,只是你忘记你。

代码下载

常用的格式就是一种封装格式比如说MKV,MP4他们就像一个容器,包含视频内容和音频内容,显然传输一个内容比分别传输视频内容和音频内容更方便,使用也更方便。对于这些容器来说,他们可以放多个内容最常见的就是一个视频内容和多个音轨,一个音轨是一个声音比如国语比如普通话和粤语或者英语!他们分别从左声道和右声道发出混合起来以后就会听上去一边是普通话一边是粤语.

会造成视频声音画面不同步的原因其实有三种:

 

可以使用播放器的选择音轨功能在视频播放的情况下,用鼠标右键点击画面来选择不同的音轨当你选定一个音轨后,电脑会把两个音轨变成相同的语音播放,你可以随时选择视频所提供的不同音轨,很多播放器都支持的比如暴风影音,QQ播放器!

1、机器配置太低,播放高码率的视频文件容易造成不同步。尝试在另外电脑上播放试下,如果是正常的,先重装系统,如果一样,可能是机子的硬件配置问题。

后台音频

后台播放音频的应用程序,顾名思义,即使用户已通过按"返回"按键或"开始"按键离开应用程序也可以继续播放音频。

你好,我是大牛哇电影!

2、片子本身就不同步。在另外的电脑上看也一样。这个就没有办法了。

后台音频体系结构

 

后台音频应用程序利用后台代理(Windows Phone OS 7.1 中的新增内容)。Windows Phone上的所有媒体都是通过Zune媒体队列播放的。后台音频应用程序向Zune媒体队列发指令控制当前堆栈、播放音乐、暂停音乐,以及快进和后退操作。那么这些是如何实现的呢?其实是调用BackgroundAudioPlayer类中方法来完成控制操作,Instance对象与Zune媒体队列通信以操作音频的播放。

有两种类型的后台音频应用程序。一种类型实现简单的播放列表并将一个包含媒体文件地址的URI传递给Zune媒体队列以设置当前曲目。URI可以是手机的本地或远程地址,在任何一种情况下,URI指向的音频必须是Windows Phone支持的类型才能播放。另一种类型的后台音频应用程序使用MediaStreamSource实现音频流的播放,此音频流的格式则可以是任何格式。这是因为由MediaStreamSource派生的类实现了对音频流的处理和解码。

1) 后台音频播放列表应用程序

 

若要创建后台音频播放列表需实现两个部分:提供用于控制播放的用户界面和实现从AudioPlayerAgent 派生的类,即下图中以绿色显示的部分。

图片 3

图后台音频播放列表应用程序

应用程序UI提供控制音频播放的用户界面。通过UI的交互调用Instance对象设置Zune媒体队列中的当前曲目。AudioPlayerAgent由操作系统进行实例化,并应用程序的用户界面或UVC处理交互操作。

AudioPlayerAgent在后台运行并调用BackgroundAudioPlayer的实例,该实例调用 Zune 媒体队列以实际播放音频。

您可使用Visual Studio中的"Windows Phone Playback Agent"模板创建新的AudioPlayerAgent项目并将该项目添加到您的解决方案中。

图片 4

图创建新的AudioPlayerAgent项目

从主应用程序项目中添加对新AudioPlayerAgent的引用。即右键单击应用程序项目中的"引用"节点,然后选择"添加引用...",如下图所示。

图片 5

图 添加引用

 

2) 音频流代理的应用程序

 

对于音频流的应用程序,需实现从AudioStreamingAgent派生的类和MediaStreamSource派生的类。您即实现下图中以绿色显示的部分。音频流代理AudioStreamingAgent 负责创建MediaStreamSource并将Zune媒体队列指向该实例。

图片 6

图 后台音频流应用程序

使用Visual Studio中的"Windows Phone Audio Streaming Agent"模板创建新的AudioStreamingAgent项目并将该项目添加到解决方案中。

图片 7

图 创建新的AudioStreamingAgent项目

3) 后台音频生命周期

AudioPlayerAgent和AudioStreamingAgent虽然都是由BackgroundAudioPlayer创建,但是其各自的生命周期却有所不同。

AudioPlayerAgent是由BackgroundAudioPlayer在需要时创建的,用于处理来自应用程序的用户界面或通用音量控制(UVC)的用户操作请求。

AudioStreamingAgent是由BackgroundAudioPlayer在需要新的音频流时创建的。当新曲目由于要开始播放而需要音频流时,BackgroundAudioPlayerAudioStreamingAgent 中调用OnBeginStreaming方法。

当后台代理调用 Abort()()()()或NotifyComplete()()()()时释放后台代理。

 

4) 实现音频播放的类

 

BackgroundAudioPlayer

BackgroundAudioPlayer类与Zune媒体队列通信,通过Instance控制正在播放的音频。调用BackgroundAudioPlayer类.aspx)的Instance属性返回BackgroundAudioPlayer的实例。如果此应用程序已分配后台音频播放资源,则返回的BackgroundAudioPlayer将包含对这些资源的引用。

注意:

每个应用程序只能有一个BackgroundAudioPlayer处于活动状态。

AudioTrack

AudioTrack类表示有关某个曲目的元数据,包括标题、艺术家、专辑以及曲目的URI。如果URI设置为null,则系统则默认曲目设置为MediaStreamSource。在这种情况下,可使用Tag属性将AudioPlayerAgent中的信息传递给AudioStreamingAgent

AudioStreamer

AudioStreamer的实例传递给OnBeginStreaming(AudioTrack, AudioStreamer)。在OnBeginStreaming的实现中,调用SetSource(MediaStreamSource)指向从MediaStreamSource派生的类。

 

一般这种情况,是因为你选择的片源有两种音轨,也就是一个国语一个外国语,明白这个原因,解决起来就简单了。大牛给出的方法就是你用播放器打开这部电影的时候,左键点击电影画面,或者点中播放器设置按钮,会出现详细设置,找到音轨选择项,可以选到你要用的语言。这样再播放就是你需要的声音了。

3、软件使用不当造成转换后的文件不同步。常见于 avi 文件和 rm/rmvb 文件。更换别的播放器,如暴风影音,PotPlayer之类的播放,看看是否正常。

后台音频的程序的认证要求

 

后台音频的程序属于特定应用程序类型,除了一般应用程序的要求需满足外,还需符合如下的要求。

1) 该应用程序不得启动后台音频播放,除非用户激活该应用程序提供的可发现 UI 元素。

验证方法:

  • 启动应用程序;
  • 验证该应用程序中是否存在可发现的UI元素,并允许后台音频播放;

  • 激活UI元素以开始后台音频播放;

  • 验证后台音频播放是否开始。

2) 当该应用程序位于前台中时,它必须向用户提供可发现的UI元素,允许用户停止音频播放。

验证方法:

  • 启动应用程序;
  • 开始音频播放;
  • 验证应用程序内是否可发现停止音频播放的UI元素;

  • 激活UI元素以停止音频播放;

  • 验证音频播放是否停止。

3) 当用户点按统一音量控制上的"停止"按键时,应用程序必须停止后台中播放的音频。如果播放服务支持暂停操作,则通过统一音量控制暂停后台音频必须根据用户的操作暂停或重新启动音频。

验证方法:

  • 启动应用程序;
  • 开始音频播放;
  • 关闭该应用程序;
  • 验证该音频是否继续在后台中播放;

  • 查看统一音量控制;

  • 如果播放服务支持暂停命令,则可以通过统一音量控制暂停音频,验证播放是否暂停;通过统一音量控制重新启动音频,验证播放是否重新启动;

  • 通过统一音量控制停止音频播放;

  • 验证播放是否停止;

4) 当从应用程序中播放后台音频时,该应用程序发送的要显示在统一音量控制中的元数据必须对该音频进行描述(例如歌曲、曲目、艺术家、播放状态或应用程序名称)。应用程序错误代码不得显示在统一音量控制中。禁止在统一音量控制中插入广告和其他不相关的内容。

验证方法:

  • 启动应用程序;
  • 开始音频播放;
  • 关闭该应用程序;
  • 验证该音频是否继续在后台中播放;

  • 查看统一音量控制;

  • 验证该音频播放的元数据是否显示以及是否与音频内容相关。

5) 使用AudioStreamingAgent API的应用程序只能用于执行与音频播放及关联元数据管理相关的任务。

验证方法:

  • 启动应用程序;
  • 关闭该应用程序;
  • 验证后台音频流代理是否仅用于传输指定音频内容及进行相关的元数据管理。

 

可以关注我,为你解答更多关于电影方面的问题,一起分享电影之旅美好的点点滴滴!

造成视频声音和画面不同步原因一是视频剪辑时造成,如果是手机看视频都出现这样的情况可能是内存不足造成。

后台音频的最佳实践

 

1) 调试

在"编码—调试—编辑代码—重新启动调试"的过程中,调试器可能会在您重新启动调试时将自身连接到后台音频代理,而不是您的应用程序。若要避免出现这种情况,您需要确保后台代理在应用程序启动时处于关闭状态。要实现这一点,有一种简便的方法是将对Close()()()()的调用放到App类的构造函数中。如果您是通过Visual Studio模板创建的应用,则App类构造函数中会包含一项检查,以了解该应用程序是否正在调试器下运行。可将对BackgroundAudioPlayer.Instance.Close的调用放在此if语句中。

// Show graphics profiling information while debugging.

if (System.Diagnostics.Debugger.IsAttached)

{

// Close the background audio player in case it

// was running from a previous debugging session.

BackgroundAudioPlayer.Instance.Close();

 

// ...

}

 

2) 处理用户操作

BackgroundAudioPlayer未对用户操作(UserAction)请求的数量施加任何限制。通过UI(应用界面或通用音量控制即UVC)调用的操作排成在队列中处理。AudioPlayerAgent没有确定是否存在连续调用的方法。需要网络请求的SkipNext、SkipPrevious或Play调用可能需要几秒钟的时间。

  • 无论调用花费的时间长短,都将按顺序处理对SkipNext、SkipPrevious或Play的连续调用。

  • 每次调用允许30秒的时间。

  • 由于Play和Pause操作未获得优先权,因此代理可能花费几秒钟(甚至几分钟)的时间才能响应用户操作。

因此限制排队的SkipNext和SkipPrevious请求的数量并给予Play和Pause较高的优先级。后台音频播放器示例只是在处理请求之前禁用"下一个""上一个"按钮。从 Windows Phone 的代码示例页面中获得后台音频播放器示例的代码。

MediaElement和BackgroundAudioPlayer

混合BackgroundAudioPlayer和MediaElement要注意:

  • 必须在切换到MediaElement 播放之前调用Close()()()()。
  • 只有一个媒体队列。您的应用程序不能暂停后台音频,不能使用 MediaElement 播放某些内容,而且不能继续播放后台音频流。

 

内存和运行时约束

  • AudioPlayerAgent 的实现必须在30秒内调用NotifyComplete()()()()或Abort()()()()。

  • AudioStreamingAgent 的实现则允许无限时运行。

  • 两种类型的后台音频代理都托管在同一进程中,并且共用最大限制为 15 MB 的内存。
  • 在调试器下运行时,Windows Phone 操作系统会忽略内存和运行时约束。

 

 

恭喜恭喜你,你是幸运的,看电影能体验双语同步的感觉。如果,只想听一种语言的话,那么办法是有的。第一,带上耳机,两个耳朵两种声音,很简单,去掉一边的耳机,即刻体验你满意的语言;第二,在播放器的声道中选择,你需要的语言;第三,干脆找只有一种语言的视频资料。好了,我的回答你满意吗?别忘了,给个赞啊!

所以解决的办法就是停掉一些不用的程序进程,设置---应用程序---正在运行的服务。

动手实践——音乐播放器

本节的重点内容是实现音乐播放器的后台音乐播放功能,即在应用程序处于非激活状态时持续的播放音乐。本节的涉及的技术如何实现使用音频播放代理播放本地媒体的 Windows Phone 应用程序。

 

任务1——创建Windows Phone后台音频应用程序

 

  • 通过选择"文件|新项目..."菜单命令创建一个新项目。

  • 将显示"新建项目"对话框。展开"Visual C#"模板,然后选择"Silverlight for Windows Phone"模板。

  • 选择"Windows Phone应用程序"模板。根据需要填写"MusicPlayer",然后单击"确定"。

  • 在"解决方案资源管理器"中,右键单击"解决方案"节点,然后选择"添加 | 新项目..."。

  • 在"添加新项目"对话框中,单击"Windows Phone音频播放代理"。
  • 在名称中填写"AudioPlaybackAgent",然后单击"确定"。至此,解决方案应该具有两个项目,即应用程序项目和后台代理项目。

 

任务2——添加UI和事件处理函数

 

在此任务中添加MainPage的UI和后台音频Microsoft.Phone.BackgroundAudio.BackgroundAudioPlayer的事件处理函数。

 

打开 MainPage.xaml 文件

在文件首部的phone:PhoneApplicationPage中绑定DataContext的相关资源属性。

 

DataContext="{Binding RelativeSource={RelativeSource Self}}"

 

定位到ContentPanel的标签,在其中添加HorizontalAlignment属性,设置其为"Stretch"。

 

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0" HorizontalAlignment="Stretch">

 

在Grid中增加对于行属性的定义和TextBlock,TextBlock绑定播放列表的名称。

 

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0" HorizontalAlignment="Stretch">

<Grid.RowDefinitions>

<RowDefinition Height="Auto"/>

<RowDefinition Height="*"/>

<RowDefinition Height="Auto"/>

</Grid.RowDefinitions>

 

<TextBlock Text="{Binding ActivePlaylist.Name}" FontSize="{StaticResource PhoneFontSizeExtraLarge}"/>

</Grid>

 

增加显示播放曲目的ListBox,代码如下。

 

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0" HorizontalAlignment="Stretch">

    <Grid.RowDefinitions>

        <RowDefinition Height="Auto"/>

        <RowDefinition Height="*"/>

        <RowDefinition Height="Auto"/>

    </Grid.RowDefinitions>

 

    <TextBlock Text="{Binding ActivePlaylist.Name}" FontSize="{StaticResource PhoneFontSizeExtraLarge}"/>

    <ListBox ItemsSource="{Binding ActivePlaylist.Tracks}" Grid.Row="1" x:Name="lstTracks" HorizontalContentAlignment="Stretch" Loaded="lstTracks_Loaded">

        <ListBox.ItemTemplate>

            <DataTemplate>

                <Grid HorizontalAlignment="Stretch">

                    <Grid.RowDefinitions>

                        <RowDefinition/>

                        <RowDefinition/>

                        <RowDefinition/>

                    </Grid.RowDefinitions>

                    <Grid.ColumnDefinitions>

                        <ColumnDefinition Width="Auto"/>

                        <ColumnDefinition Width="*"/>

                    </Grid.ColumnDefinitions>

 

                    <Image Margin="10,0" Source="{Binding Tile, TargetNullValue={StaticResource NoArt}}" Grid.RowSpan="3" Width="60" Stretch="Uniform" VerticalAlignment="Center"/>

                    <TextBlock Text="{Binding Title}" Grid.Column="1" FontSize="{StaticResource PhoneFontSizeLarge}"/>

                    <TextBlock Text="{Binding Artist}" Grid.Row="1" Grid.Column="1"/>

                    <TextBlock Text="{Binding Album}" Grid.Row="2" Grid.Column="1"/>

                </Grid>

            </DataTemplate>

        </ListBox.ItemTemplate>

    </ListBox>

</Grid>

 

打开MainPage.xaml.cs,添加命名为lstTracks_Loaded的函数。

 

publicpartialclassMainPage : PhoneApplicationPage

{

    ...

    private void lstTracks_Loaded(object sender, RoutedEventArgs e)

    {

    }

    ...

}

 

编译并在模拟器中运行的效果如下所示。

图片 8

图 运行效果

 

定义播放列表类Playlist的依赖属性,将其命名为ActivePlaylist

 

publicpartialclassMainPage : PhoneApplicationPage

{

    public Playlist ActivePlaylist

    {

        get { return (Playlist)GetValue(ActivePlaylistProperty); }

        set { SetValue(ActivePlaylistProperty, value); }

    }

 

右键单击系统栏的声音图标,并按下“打开音量控制”⑵、接下来会出现“音量控制”设置面板,请您按图中所示将“音量控制”和“波形”两栏的“平衡”游标都拖至最左端,如果您听到的还不是国语对白,请继续下面第三步。⑶、如果第二步的操作还不能让您听到国语对白,那么请您再把两处的游标都拖至最右端,至此,您应该可以听到熟悉的国语对白了

其次,保持优良的网络环境。

    public static readonly DependencyProperty ActivePlaylistProperty

    DependencyProperty.Register("ActivePlaylist", typeof(Playlist), typeof(MainPage), newPropertyMetadata(null));

    ...

}

 

重载OnNavigatedTo方法,读取独立存储空间中的播放列表。

 

publicpartialclassMainPage : PhoneApplicationPage

{

    ...

    protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)

    {

        Stream playlistStream = Application.GetResourceStream(new Uri("Misc/Playlist.xml", UriKind.Relative)).Stream;

 

        System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(Playlist));

        ActivePlaylist = (Playlist)serializer.Deserialize(playlistStream);

 

        using ( IsolatedStorageFile isoStorage = IsolatedStorageFile.GetUserStoreForApplication() )

        {

            using ( IsolatedStorageFileStream file = isoStorage.OpenFile("playlist.xml", FileMode.OpenOrCreate) )

            {

                var writer = new StreamWriter(file);

 

                serializer.Serialize(writer, ActivePlaylist);

            }

        }

 

        base.OnNavigatedTo(e);

    }

    ...

}

 

在MainPage的构造函数中,添加PlayStateChanged事件订阅的代码。

 

publicpartialclassMainPage : PhoneApplicationPage

{

    ...

    public MainPage()

    {

        InitializeComponent();

 

        BackgroundAudioPlayer.Instance.PlayStateChanged += new EventHandler(Instance_PlayStateChanged);

    }

    ...

}

 

添加事件处理函数的响应代码,实现当后台音频播放器运行时,更新播放曲目和播放状态。

 

publicpartialclassMainPage : PhoneApplicationPage

{

    ...

    privatevoid Instance_PlayStateChanged(object sender, EventArgs e)

    {

        UpdateSelection();

    }

 

    privatevoid UpdateSelection()

    {

        int activeTrackNumber = GetActiveTrackIndex();

 

        if ( activeTrackNumber != -1 )

        {

            lstTracks.SelectedIndex = activeTrackNumber;

        }

    }

 

    privateint GetActiveTrackIndex()

    {

        int track = -1;

        if ( null != BackgroundAudioPlayer.Instance.Track )

        {

            track = int.Parse(BackgroundAudioPlayer.Instance.Track.Tag);

        }

 

        return track;

    }

    ...

}

 

在应用程序处于不活动状态时,后台音频播放器也允许用户更改播放的曲目。若要实现此功能,需要更新的lstTracks_Loaded方法,在该方法中插入以下代码。

 

publicpartialclassMainPage : PhoneApplicationPage

{

    ...

    private void lstTracks_Loaded(object sender, RoutedEventArgs e)

    {

        UpdateSelection();

    }

    ...

}

 

编译并运行此程序,首页呈现的内容如下。

 

图片 9

  1. 图 播放列表

    任务3——添加控制按钮

    本节中将添加ApplicationBar的按钮,控制音乐播放器播放、停止、前一个音轨和后一个音轨。

    MainPage.xaml添加PhoneApplicationPage.ApplicationBar,即在LayoutRoot结尾部分添加如下的代码。

     

    <phone:PhoneApplicationPage.ApplicationBar>

    <shell:ApplicationBar IsVisible="True" IsMenuEnabled="False">

    <shell:ApplicationBarIconButton IconUri="/Images/prev.png" Text="prev" Click="appbar_prev"/>

    <shell:ApplicationBarIconButton IconUri="/Images/play.png" Text="play" Click="appbar_playpause"/>

    <shell:ApplicationBarIconButton IconUri="/Images/stop.png" Text="stop" Click="appbar_stop"/>

    <shell:ApplicationBarIconButton IconUri="/Images/next.png" Text="next" Click="appbar_next"/>

    </shell:ApplicationBar>

    </phone:PhoneApplicationPage.ApplicationBar>

     

    MainPage.xaml.cs添加应用程序栏(ApplicationBar)的Click事件处理函数。

     

    public partial class MainPage : PhoneApplicationPage

    {

            ...

            #region ApplicationBar Buttons Events

            private void appbar_prev(object sender, EventArgs e)

            {

                BackgroundAudioPlayer.Instance.SkipPrevious();

            }

     

            private void appbar_playpause(object sender, EventArgs e)

            {

                if ( BackgroundAudioPlayer.Instance.PlayerState == PlayState.Playing )

                    BackgroundAudioPlayer.Instance.Pause();

                else

                    BackgroundAudioPlayer.Instance.Play();

            }

     

            private void appbar_stop(object sender, EventArgs e)

            {

                BackgroundAudioPlayer.Instance.Stop();

            }

     

            private void appbar_next(object sender, EventArgs e)

            {

                BackgroundAudioPlayer.Instance.SkipNext();

            }

            #endregion

            ...

    }

    Instance_PlayStateChanged方法中更新应用程序栏的按钮状态,为此调用UpdateAppBarStatus方法。

     

    publicpartialclassMainPage : PhoneApplicationPage

    {

        ...

        privatevoid Instance_PlayStateChanged(object sender, EventArgs e)

    { 

        UpdateAppBarStatus(); 

        UpdateSelection(); 

    } 

    ...

} 

实现**UpdateAppBarStatus** 方法。判断BackgroundAudioPlayer的状态是处于播放、暂停和停止的状态,然后分别设置"前一个"、"播放/暂停"、"停止"和"下一个"按钮的状态。

 

publicpartialclassMainPage : PhoneApplicationPage

{

    ...

    privatevoid UpdateAppBarStatus()

    {

        switch ( BackgroundAudioPlayer.Instance.PlayerState )

        {

            case PlayState.Playing:

                //Prev Button

                if ( GetActiveTrackIndex() > 0 )

                    ( ApplicationBar.Buttons[0] as ApplicationBarIconButton ).IsEnabled = true;

                else

                    ( ApplicationBar.Buttons[0] as ApplicationBarIconButton ).IsEnabled = false;

 

                //Play/Pause Button

                ( ApplicationBar.Buttons[1] as ApplicationBarIconButton ).IsEnabled = true;

                ( ApplicationBar.Buttons[1] as ApplicationBarIconButton ).Text = "pause";

                ( ApplicationBar.Buttons[1] as ApplicationBarIconButton ).IconUri = new Uri("/Images/pause.png", UriKind.Relative);

 

                //Stop Button

                ( ApplicationBar.Buttons[2] as ApplicationBarIconButton ).IsEnabled = true;

 

                //Next button

                if ( GetActiveTrackIndex() < ActivePlaylist.Tracks.Count - 1 )

                    ( ApplicationBar.Buttons[3] as ApplicationBarIconButton ).IsEnabled = true;

                else

                    ( ApplicationBar.Buttons[3] as ApplicationBarIconButton ).IsEnabled = false;

                break;

 

            case PlayState.Paused:

                //Prev Button

                if ( GetActiveTrackIndex() > 0 )

                    ( ApplicationBar.Buttons[0] as ApplicationBarIconButton ).IsEnabled = true;

                else

                    ( ApplicationBar.Buttons[0] as ApplicationBarIconButton ).IsEnabled = false;

 

                //Play/Pause Button

                ( ApplicationBar.Buttons[1] as ApplicationBarIconButton ).IsEnabled = true;

                ( ApplicationBar.Buttons[1] as ApplicationBarIconButton ).Text = "play";

                ( ApplicationBar.Buttons[1] as ApplicationBarIconButton ).IconUri = new Uri("/Images/play.png", UriKind.Relative);

 

                //Stop Button

                ( ApplicationBar.Buttons[2] as ApplicationBarIconButton ).IsEnabled = true;

 

                //Next button

                if ( GetActiveTrackIndex() < ActivePlaylist.Tracks.Count - 1 )

                    ( ApplicationBar.Buttons[3] as ApplicationBarIconButton ).IsEnabled = true;

                else

                    ( ApplicationBar.Buttons[3] as ApplicationBarIconButton ).IsEnabled = false;

                break;

 

            case PlayState.Stopped:

                //Prev Button

                if ( GetActiveTrackIndex() > 0 )

                    ( ApplicationBar.Buttons[0] as ApplicationBarIconButton ).IsEnabled = true;

                else

                    ( ApplicationBar.Buttons[0] as ApplicationBarIconButton ).IsEnabled = false;

 

                //Play/Pause Button

                ( ApplicationBar.Buttons[1] as ApplicationBarIconButton ).IsEnabled = true;

                ( ApplicationBar.Buttons[1] as ApplicationBarIconButton ).Text = "play";

                ( ApplicationBar.Buttons[1] as ApplicationBarIconButton ).IconUri = new Uri("/Images/play.png", UriKind.Relative);

 

                //Stop Button

                ( ApplicationBar.Buttons[2] as ApplicationBarIconButton ).IsEnabled = false;

 

                //Next button

                if ( GetActiveTrackIndex() < ActivePlaylist.Tracks.Count - 1 )

                    ( ApplicationBar.Buttons[3] as ApplicationBarIconButton ).IsEnabled = true;

                else

                    ( ApplicationBar.Buttons[3] as ApplicationBarIconButton ).IsEnabled = false;

                break;

 

            case PlayState.Unknown:

                //Prev Button

                ( ApplicationBar.Buttons[0] as ApplicationBarIconButton ).IsEnabled = false;

 

                //Play/Pause Button

                ( ApplicationBar.Buttons[1] as ApplicationBarIconButton ).IsEnabled = true;

                ( ApplicationBar.Buttons[1] as ApplicationBarIconButton ).Text = "play";

                ( ApplicationBar.Buttons[1] as ApplicationBarIconButton ).IconUri = new Uri("/Images/play.png", UriKind.Relative);

 

                //Stop Button

                ( ApplicationBar.Buttons[2] as ApplicationBarIconButton ).IsEnabled = false;

 

                //Next button

                if ( GetActiveTrackIndex() < ActivePlaylist.Tracks.Count - 1 )

                    ( ApplicationBar.Buttons[3] as ApplicationBarIconButton ).IsEnabled = true;

                else

                    ( ApplicationBar.Buttons[3] as ApplicationBarIconButton ).IsEnabled = false;

                break;

 

            default:

                break;

        }

    }

    ...

}

编译和运行应用程序,可以看到播放列表下方新增了应用程序栏。

图片 10

图 具有应用程序栏的播放列表

 

  1. 任务4——在独立存储空间保存音乐和图像文件

您可能会疑惑为什么要将曲目保存至独立存储空间,答案很简单,就是为了能够被播放器播放。

App.xaml.cs的文件头部添加如下的引用

 

using System.IO.IsolatedStorage;

using System.Windows.Resources;

  1.  

    App类的构造函数中,添加调用CopyToIsolatedStorage方法的代码,并实现CopyToIsolatedStorage的代码:创建IsolatedStorageFile对象引用独立存储空间的类,将音频文件写入独立存储空间的"Music/"文件夹中,将专辑图片写入独立存储空间的"Shared/Media/"文件夹中。

     

    public App()

    {

        ...

        CopyToIsolatedStorage();

    }

     

    private void CopyToIsolatedStorage()

    {

        using ( IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication() )

        {

            string[] files = new string[] { "file1.mp3", "file2.mp3", "file3.mp3" };

     

            foreach ( var _fileName in files )

            {

                if ( !storage.FileExists(_fileName) )

                {

                    string _filePath = "Music/" + _fileName;

                    StreamResourceInfo resource = Application.GetResourceStream(new Uri(_filePath, UriKind.Relative));

     

                    using ( IsolatedStorageFileStream file = storage.CreateFile(_fileName) )

                    {

                        int chunkSize = 4096;

                        byte[] bytes = new byte[chunkSize];

                        int byteCount;

     

                        while ( ( byteCount = resource.Stream.Read(bytes, 0, chunkSize) ) > 0 )

                        {

                            file.Write(bytes, 0, byteCount);

                        }

                    }

                }

            }

     

            files = new string[] { "Image1.jpg", "Image3.jpg", "no-art.jpg" };

     

            foreach ( var _fileName in files )

            {

                string _destFilePath = "Shared/Media/" + _fileName;

                ;

                if ( !storage.FileExists(_destFilePath) )

                {

                    string _filePath = "Images/" + _fileName;

                    StreamResourceInfo resource = Application.GetResourceStream(new Uri(_filePath, UriKind.Relative));

     

                    using ( IsolatedStorageFileStream file = storage.CreateFile(_destFilePath) )

                    {

                        int chunkSize = 4096;

                        byte[] bytes = new byte[chunkSize];

                        int byteCount;

     

                        while ( ( byteCount = resource.Stream.Read(bytes, 0, chunkSize) ) > 0 )

                        {

                            file.Write(bytes, 0, byteCount);

                        }

                    }

                }

            }

        }

    }

  2.  

    1. 任务5——音频播放的后台代理

    后台音频播放的代理运行在后台,是由操作系统实例化的对象,用来处理用户的后台运行请求。AudioPlayerAgent在后台运行,调用BackgroundAudioPlayer播放Zune媒体队列。

    在解决方案中添加新的工程,工程模板为Windows Phone Audio Playback AgentWindows Phone Audio Playback Agent模板位于Silverlight for Windows Phone 类别中,将新工程命名为AudioPlaybackAgent

    在此工程中需要用到model的定义和XML的序列化,所以在工程的引用中添加ModelsSystem.Xml.Serialization的引用。

    AudioPlayer.cs中重构AudioPlayer类。删除原有的代码,在文件的头部添加引用,代码如下。

     

    using System.IO.IsolatedStorage;

    using System.Xml.Serialization;

    using System.IO;

    using Models;

     

    AudioPlayer类中添加静态变量currentTrackNumber和playlist。currentTrackNumber保存当前播放的音轨,playlist保存当前的播放列表。

     

    static int currentTrackNumber = 0;

    static Playlist playlist;

     

    AudioPlayer的构造函数,从独立存储空间读取XML格式的文件列表。

     

    public AudioPlayer()

        : base()

    {

     

        //Load from IsoStore & deserialize 

        using ( IsolatedStorageFile isoStorage = IsolatedStorageFile.GetUserStoreForApplication() )

        {

            using ( IsolatedStorageFileStream file = isoStorage.OpenFile("playlist.xml", FileMode.Open) )

            {

                XmlSerializer serializer = new XmlSerializer(typeof(Playlist));

                var reader = new StreamReader(file);

     

                playlist = (Playlist)serializer.Deserialize(reader);

            }

        }

    }

     

    重载OnPlayStateChanged 方法,实现处理播放器的状态变化。其中调用NotifyComplete方法通知后台音频播放器状态的变化。

     

    protected override void OnPlayStateChanged(BackgroundAudioPlayer player, AudioTrack track, PlayState playState)

    {

        switch ( playState )

        {

            case PlayState.TrackEnded:

                PlayNext(player);

                break;

            case PlayState.TrackReady:

                player.Play();

                break;

            default:

                break;

        }

     

        NotifyComplete();

    }

     

    添加PlayNext和PlayPrev方法,实现上一个和下一个音轨的播放。

     

    private void PlayNext(BackgroundAudioPlayer player)

    {

        var songsCount = playlist.Tracks.Count;

     

        if ( ++currentTrackNumber >= songsCount )

        {

            currentTrackNumber = 0;

        }

        Play(player);

     

    }

    private void PlayPrev(BackgroundAudioPlayer player)

    {

        var songsCount = playlist.Tracks.Count;

        if ( --currentTrackNumber < 0 )

        {

            currentTrackNumber = songsCount - 1;

        }

        Play(player);

    }

     

    重载OnUserAction方法,处理后台音频播放器与用户触控的交互。

     

    protected override void OnUserAction(BackgroundAudioPlayer player, AudioTrack track, UserAction action, object param)

    {

        switch ( action )

        {

            case UserAction.FastForward:

                player.FastForward();

                break;

            case UserAction.Pause:

                player.Pause();

                break;

            case UserAction.Play:

                if ( player.PlayerState == PlayState.Paused )

                {

                    player.Play();

                }

                else

                {

                    Play(player);

                }

                break;

            case UserAction.Rewind:

                player.Rewind();

                break;

            case UserAction.Seek:

                player.Position = (TimeSpan)param;

                break;

            case UserAction.SkipNext:

                PlayNext(player);

                break;

            case UserAction.SkipPrevious:

                PlayPrev(player);

                break;

            case UserAction.Stop:

                player.Stop();

                break;

            default:

                break;

        }

     

        NotifyComplete();

    }

     

    实现初始化播放当前音轨的方法:从播放列表中获取当前音轨的源、标题、艺术家和专辑等信息,以此信息实例化AudioTrack类并播放。

     

    private void Play(BackgroundAudioPlayer player)

    {

        var currentTrack = playlist.Tracks[currentTrackNumber];

        Uri tileUri = ( currentTrack.Tile == null ? new Uri("Shared/Media/no-art.jpg", UriKind.Relative) :

                                                   ( currentTrack.Tile.IsAbsoluteUri ? new Uri("Shared/Media/no-art.jpg", UriKind.Relative) :

                                                                                      new Uri(currentTrack.TileString.Replace("/Images", "Shared/Media"), UriKind.Relative) ) );

     

        var audioTrack = new AudioTrack(currentTrack.Source,

                                      currentTrack.Title,

                                      currentTrack.Artist,

                                      currentTrack.Album,

                                      tileUri,

                                      currentTrackNumber.ToString(),

                                      EnabledPlayerControls.All);

        player.Track = audioTrack;

    }

     

    最后一步,在MusicPlayer项目中添加AudioPlaybackAgent项目的引用。

     

    任务6——测试应用程序

    运行应用程序,单击播放按钮图片 11。确认在键盘上按F9键可增加模拟器的音量,按F10键可降低模拟器的音量。

    图片 12

    图4 在模拟器中运行

    按下启动键图片 13,确认音乐可以继续播放。

    图片 14

    图5 后台音频播放控制器

    在键盘上按下F9键显示后台音频播放器的控制界面,通过触控按钮控制当前播放的曲目。

更改声道就可:

造成影音不同步的原因可能有多种,不同的原因要用不同的对策。

打开Media play classic 在"播放"的菜单中

1.低配置的播放对策

选择“音频”“选项”,就可以打开“音频切换器”里面“扬声器配置为2个输入声道”然后在下面的选项

电脑硬件配置太低实在是很无奈的事,如果暂时没有条件升级,可使用Mplayer播放器。这个播放器对硬件相求相当低,在赛扬500这种档次的机器上就可以流畅地播放高码率的DVDRip了。

选择一个声道,点应用即可。

2.更换解码器

更改声道就行了打开Media play classic 在"播放"的菜单中选择“音频”“选项”,就可以打开“音频切换器”里面“扬声器配置为2个输入声道”然后在下面的选项选择一个声道,就能解决了

如音频不流畅可以更换一种音频解码器,对于DivX、XviD视频可以考虑换一种兼容解码器。方法前面有介绍。

更改声道就可:打开Media play classic 在"播放"的菜单中选择“音频”“选项”,就可以打开“音频切换器”里面“扬声器配置为2个输入声道”然后在下面的选项选择一个声道,点应用即可。

3.整理磁盘碎片

硬盘的碎片过多可能会导致播放不流畅,造成影音不同步。整理一下硬盘往往会有很好的效果

4.解决设置不当的问题

还有一种同步是由于在VobSub字幕插件中设置了强制帧率造成的,可在播放时双击系统托盘中的VobSub图标,打开其属性对话框,在“同步”选项卡中,检查是否选定了“强制帧率”复选框,如果选定了可取消它。

5.视频文件本身音视频不同步的处理

有些电影是由于制作的原因而造成了影音不能同步。对于这样的文件,如果不想重新编码,可在使用Media Player Classic播放时进行调整。

在播放时先估计好延时的时间,然后选择“查看”看菜单中的“选项”命令,打开“选项”对话框,从中选择“音频切换器”,并在右边选定“声音延迟时间”复选框,然后在后面的数值框中输入时间。

本文由必赢手机登录网址发布于科技产品,转载请注明出处:Mango开发实践,为什么看视频时声音和画面不同步

您可能还会对下面的文章感兴趣: