【问题标题】:Android: video saved to gallery won't playAndroid:保存到图库的视频无法播放
【发布时间】:2015-10-07 12:41:04
【问题描述】:

我有一个相当奇怪的问题。我正在使用 Xamarin 框架编写一个 Android 应用程序,并且我还有一个同样用 Xamarin 编写的同一应用程序的 iOS 版本。在应用程序中,用户可以将照片和视频发送给他们的朋友,他们的朋友可能在 iOS 或 Android 上。这一切都很好,在 iPhone 上拍摄的视频可以在 Android 设备上播放,反之亦然。

我遇到的问题是,当我尝试以编程方式将视频保存到 Android 库时,该视频无法在库中播放。看来它自己的视频数据实际上是被复制的,但视频不知何故无法播放。

我的视频使用 H.264 编解码器编码为 mp4 格式。我相信 Android 完全支持这一点,就像我说的那样,当通过应用中的 VideoView 播放视频时,视频播放得很好。

我用来将视频复制到图库的代码如下。有谁知道我在这里做错了什么?

public static void SaveVideoToGallery(Activity activity, String filePath) {

    // get filename from path
    int idx = filePath.LastIndexOf("/") + 1;
    String name = filePath.Substring(idx, filePath.Length - idx);

    // set in/out files
    File inFile = new File(filePath);
    File outDir = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryMovies);
    File outFile = new File(outDir, name);

    // Make sure the Pictures directory exists.
    outDir.Mkdirs();

    // save the file to disc
    InputStream iStream = new FileInputStream(inFile);
    OutputStream oStream = new FileOutputStream(outFile);
    byte[]data = new byte[iStream.Available()];
    iStream.Read();
    oStream.Write(data);
    iStream.Close();
    oStream.Close();

    // Tell the media scanner about the new file so that it is
    // immediately available to the user.
    MediaScannerConnection.ScanFile(
        activity.ApplicationContext,
        new String[] { outFile.ToString() }, 
        null,
        null);
}

注意:我知道这一切都在 C# 中,但请记住,Xamarin 框架所做的只是为原生 Android 方法提供 API。我使用的一切都是 Java 或 Android 支持的类/函数。

谢谢!

【问题讨论】:

    标签: android xamarin xamarin.ios


    【解决方案1】:

    您的问题在于这段代码 sn-p:

    byte[]data = new byte[iStream.Available()];
    iStream.Read();
    oStream.Write(data);
    

    这里有几个问题:

    • 您永远不会将文件内容读入data 缓冲区; iStream.Read() 只会读取一个字节并将其作为整数返回。
    • new byte[iStream.Available()] 将仅分配可在不阻塞的情况下读取的数据字节量。这不是完整的文件。请参阅有关 available 方法的文档。
    • oStream.Write(data) 写出一个垃圾数据块,因为它没有被读取。

    最终结果是输出的视频文件只是一块空数据,因此画廊无法使用它。

    修复它从文件流中读取数据,然后将它们写入输出文件:

        int bytes = 0;
        byte[] data = new byte[1024];
        while ((bytes = iStream.Read(data)) != -1) 
        { 
            oStream.Write (data, 0, bytes);
        }
    

    完整样本:

    public static void SaveVideoToGallery(Activity activity, String filePath) {
    
        // get filename from path
        int idx = filePath.LastIndexOf("/") + 1;
        String name = filePath.Substring(idx, filePath.Length - idx);
    
        // set in/out files
        File inFile = new File(filePath);
        File outDir = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryMovies);
        File outFile = new File(outDir, name);
    
        // Make sure the Pictures directory exists.
        outDir.Mkdirs();
    
        // save the file to disc
        InputStream iStream = new FileInputStream(inFile);
        OutputStream oStream = new FileOutputStream(outFile);
    
        int bytes = 0;
        byte[] data = new byte[1024];
        while ((bytes = iStream.Read(data)) != -1) 
        { 
            oStream.Write (data, 0, bytes);
        }
    
        iStream.Close();
        oStream.Close();
    
        // Tell the media scanner about the new file so that it is
        // immediately available to the user.
        MediaScannerConnection.ScanFile(
            activity.ApplicationContext,
            new String[] { outFile.ToString() }, 
            null,
            null);
    }
    

    【讨论】:

    • 好吧,我在写它的时候认为特定区域很奇怪,但我遵循的是 Android 文档中的一个示例,所以只是假设它是正确的。我试过了,现在效果很好,所以感谢您的帮助和出色的信息。我确实有一个问题。如果“new byte[1024]”这一行创建了一个大小为 1024 字节的字节数组,那么它如何能够容纳超过 1024 字节的数据呢?可能是一个愚蠢的问题,但我现在很好奇。
    • 这根本不是一个愚蠢的问题,1024 是一个临时缓冲区,它占用iStream 文件的小块,然后将其附加到oStream。它会根据需要多次重复使用,以复制整个文件。
    • 啊,我明白了,每次传递都需要从数据中提取 1024 个块,直到完成。说得通。谢谢哥们!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-29
    • 1970-01-01
    • 2015-10-09
    • 1970-01-01
    • 1970-01-01
    • 2012-11-07
    相关资源
    最近更新 更多