我使用以下代码构建了视频播放器
https://github.com/xamarin/xamarin-forms-samples/tree/master/CustomRenderers/VideoPlayerDemos
在引用网络视频时,该视频可以正常播放,但是当我尝试从资源文件夹中绘制视频时,该视频不起作用,模拟器显示以下错误:
07-13 15:53:12.148 W/MediaPlayer(10655): Couldn't open android.resource://com.companyname.ListManipulation/raw/sintel-2048-stereo_512kb: java.io.FileNotFoundException: No resource found for: android.resource://com.companyname.ListManipulation/raw/sintel-2048-stereo_512kb
...
07-13 15:53:12.371 E/MediaPlayer(10655): Error (1,-2147483648)
07-13 15:53:12.371 D/VideoView(10655): Error: 1,-2147483648
Xaml看起来像这样
<video:VideoPlayer HeightRequest="220" WidthRequest="320">
<video:VideoPlayer.Source>
<video:ResourceVideoSource>
<video:ResourceVideoSource.Path>
<OnPlatform x:TypeArguments="x:String">
<On Platform="iOS" Value="Videos/sintel-2048 stereo_512kb.mp4" />
<On Platform="Android" Value="sintel-2048 stereo_512kb.mp4" />
<On Platform="UWP" Value="Videos/sintel-2048 stereo_512kb.mp4" />
</OnPlatform>
</video:ResourceVideoSource.Path>
</video:ResourceVideoSource>
</video:VideoPlayer.Source>
</video:VideoPlayer>
另一个可能会产生影响的代码是
URI源类
namespace ListManipulation.FormsVideoLibrary
{
public class UriVideoSource : VideoSource
{
public static readonly BindableProperty UriProperty =
BindableProperty.Create(nameof(Uri), typeof(string), typeof(UriVideoSource));
public string Uri
{
set { SetValue(UriProperty, value); }
get { return (string)GetValue(UriProperty); }
}
}
}
ResourceVideoSource类
namespace ListManipulation.FormsVideoLibrary
{
public class ResourceVideoSource : VideoSource
{
public static readonly BindableProperty PathProperty =
BindableProperty.Create(nameof(Path), typeof(string), typeof(ResourceVideoSource));
public string Path
{
set { SetValue(PathProperty, value); }
get { return (string)GetValue(PathProperty); }
}
}
}
VideoSource类
namespace ListManipulation.FormsVideoLibrary
{
[TypeConverter(typeof(VideoSourceConverter))]
public abstract class VideoSource : Element
{
public static VideoSource FromUri(string uri)
{
return new UriVideoSource() { Uri = uri };
}
public static VideoSource FromFile(string file)
{
return new FileVideoSource() { File = file };
}
public static VideoSource FromResource(string path)
{
return new ResourceVideoSource() { Path = path };
}
}
VideoSourceConverter类
namespace ListManipulation.FormsVideoLibrary
{
public class VideoSourceConverter : TypeConverter
{
public override object ConvertFromInvariantString(string value)
{
if (!String.IsNullOrWhiteSpace(value))
{
Uri uri;
return Uri.TryCreate(value, UriKind.Absolute, out uri) && uri.Scheme != "file" ?
VideoSource.FromUri(value) : VideoSource.FromResource(value);
}
throw new InvalidOperationException("Cannot convert null or whitespace to ImageSource");
}
}
}
VideoPlayerRenderer.droid类
[assembly: ExportRenderer(typeof(ListManipulation.FormsVideoLibrary.VideoPlayer),
typeof(ListManipulation.Droid.VideoPlayerRenderer))]
namespace ListManipulation.Droid
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, ARelativeLayout>
{
VideoView videoView;
MediaController mediaController; // Used to display transport controls
bool isPrepared;
public VideoPlayerRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)
{
base.OnElementChanged(args);
if (args.NewElement != null)
{
if (Control == null)
{
// Save the VideoView for future reference
videoView = new VideoView(Context);
// Put the VideoView in a RelativeLayout
ARelativeLayout relativeLayout = new ARelativeLayout(Context);
relativeLayout.AddView(videoView);
// Center the VideoView in the RelativeLayout
ARelativeLayout.LayoutParams layoutParams =
new ARelativeLayout.LayoutParams(LayoutParams.MatchParent, LayoutParams.MatchParent);
layoutParams.AddRule(LayoutRules.CenterInParent);
videoView.LayoutParameters = layoutParams;
// Handle a VideoView event
videoView.Prepared += OnVideoViewPrepared;
SetNativeControl(relativeLayout);
}
SetAreTransportControlsEnabled();
SetSource();
args.NewElement.UpdateStatus += OnUpdateStatus;
args.NewElement.PlayRequested += OnPlayRequested;
args.NewElement.PauseRequested += OnPauseRequested;
args.NewElement.StopRequested += OnStopRequested;
}
if (args.OldElement != null)
{
args.OldElement.UpdateStatus -= OnUpdateStatus;
args.OldElement.PlayRequested -= OnPlayRequested;
args.OldElement.PauseRequested -= OnPauseRequested;
args.OldElement.StopRequested -= OnStopRequested;
}
}
protected override void Dispose(bool disposing)
{
if (Control != null && videoView != null)
{
videoView.Prepared -= OnVideoViewPrepared;
}
if (Element != null)
{
Element.UpdateStatus -= OnUpdateStatus;
}
base.Dispose(disposing);
}
void OnVideoViewPrepared(object sender, EventArgs args)
{
isPrepared = true;
((IVideoPlayerController)Element).Duration = TimeSpan.FromMilliseconds(videoView.Duration);
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args)
{
base.OnElementPropertyChanged(sender, args);
if (args.PropertyName == VideoPlayer.AreTransportControlsEnabledProperty.PropertyName)
{
SetAreTransportControlsEnabled();
}
else if (args.PropertyName == VideoPlayer.SourceProperty.PropertyName)
{
SetSource();
}
else if (args.PropertyName == VideoPlayer.PositionProperty.PropertyName)
{
if (Math.Abs(videoView.CurrentPosition - Element.Position.TotalMilliseconds) > 1000)
{
videoView.SeekTo((int)Element.Position.TotalMilliseconds);
}
}
}
void SetAreTransportControlsEnabled()
{
if (Element.AreTransportControlsEnabled)
{
mediaController = new MediaController(Context);
mediaController.SetMediaPlayer(videoView);
videoView.SetMediaController(mediaController);
}
else
{
videoView.SetMediaController(null);
if (mediaController != null)
{
mediaController.SetMediaPlayer(null);
mediaController = null;
}
}
}
void SetSource()
{
isPrepared = false;
bool hasSetSource = false;
if (Element.Source is UriVideoSource)
{
string uri = (Element.Source as UriVideoSource).Uri;
if (!String.IsNullOrWhiteSpace(uri))
{
videoView.SetVideoURI(Android.Net.Uri.Parse(uri));
hasSetSource = true;
}
}
else if (Element.Source is FileVideoSource)
{
string filename = (Element.Source as FileVideoSource).File;
if (!String.IsNullOrWhiteSpace(filename))
{
videoView.SetVideoPath(filename);
hasSetSource = true;
}
}
else if (Element.Source is ResourceVideoSource)
{
string package = Context.PackageName;
string path = (Element.Source as ResourceVideoSource).Path;
if (!String.IsNullOrWhiteSpace(path))
{
string filename = Path.GetFileNameWithoutExtension(path).ToLowerInvariant();
string uri = "android.resource://" + package + "/raw/" + filename;
videoView.SetVideoURI(Android.Net.Uri.Parse(uri));
hasSetSource = true;
}
}
if (hasSetSource && Element.AutoPlay)
{
videoView.Start();
}
}
// Event handler to update status
void OnUpdateStatus(object sender, EventArgs args)
{
VideoStatus status = VideoStatus.NotReady;
if (isPrepared)
{
status = videoView.IsPlaying ? VideoStatus.Playing : VideoStatus.Paused;
}
((IVideoPlayerController)Element).Status = status;
// Set Position property
TimeSpan timeSpan = TimeSpan.FromMilliseconds(videoView.CurrentPosition);
((IElementController)Element).SetValueFromRenderer(VideoPlayer.PositionProperty, timeSpan);
}
// Event handlers to implement methods
void OnPlayRequested(object sender, EventArgs args)
{
videoView.Start();
}
void OnPauseRequested(object sender, EventArgs args)
{
videoView.Pause();
}
void OnStopRequested(object sender, EventArgs args)
{
videoView.StopPlayback();
}
}
}
我已将相关文件存储在android原始文件中
对不起,我对此非常了解,但是我对此感到困惑不已。