在Android上没有预览的Camera2视频录制:mp4输出文件无法完全播放

时间:2016-06-11 19:01:26

标签: video mp4 codec mediarecorder android-camera2

我正在尝试在我的三星Galaxy S6(支持1920x1080,大约30 fps)上从后置摄像头(面向脸部的摄像头)录制视频。如果我不需要,我不想使用任何表面进行预览,因为这只是在后台发生。

我似乎让它工作,但输出文件无法以实际上正确的方式播放。在我的Windows 10 PC上,Windows Media Player将显示第一帧然后播放音频,VLC将不会显示任何帧。在我的手机上,录制的文件可播放但不完全。它将保持第一帧5-8秒,然后在最后,剩余时间变为0,显示的总时间改变,然后实际视频帧开始播放。在我的Mac上(10.9.5)Quicktime不会显示视频(尽管没有错误),但Google Picasa可以完美播放。我想在我的电脑上尝试使用Picasa查看它是否在那里工作,但我已经无法下载谷歌Picasa,因为它已经落日了。

我尝试安装我发现的Windows编解码器包,但是没有解决任何问题。 MediaInfo v0.7.85报告了有关该文件的信息:

General
Complete name               : C:\...\1465655479915.mp4
Format                      : MPEG-4
Format profile              : Base Media / Version 2
Codec ID                    : mp42 (isom/mp42)
File size                   : 32.2 MiB
Duration                    : 15s 744ms
Overall bit rate            : 17.1 Mbps
Encoded date                : UTC 2016-06-11 14:31:50
Tagged date                 : UTC 2016-06-11 14:31:50
com.android.version         : 6.0.1

Video
ID                          : 1
Format                      : AVC
Format/Info                 : Advanced Video Codec
Format profile              : High@L4
Format settings, CABAC      : Yes
Format settings, ReFrames   : 1 frame
Format settings, GOP        : M=1, N=30
Codec ID                    : avc1
Codec ID/Info               : Advanced Video Coding
Duration                    : 15s 627ms
Bit rate                    : 16.2 Mbps
Width                       : 1 920 pixels
Height                      : 1 080 pixels
Display aspect ratio        : 16:9
Frame rate mode             : Variable
Frame rate                  : 0.000 (0/1000) fps
Minimum frame rate          : 0.000 fps
Maximum frame rate          : 30.540 fps
Color space                 : YUV
Chroma subsampling          : 4:2:0
Bit depth                   : 8 bits
Scan type                   : Progressive
Stream size                 : 0.00 Byte (0%)
Source stream size          : 31.7 MiB (98%)
Title                       : VideoHandle
Language                    : English
Encoded date                : UTC 2016-06-11 14:31:50
Tagged date                 : UTC 2016-06-11 14:31:50
mdhd_Duration               : 15627

Audio
ID                          : 2
Format                      : AAC
Format/Info                 : Advanced Audio Codec
Format profile              : LC
Codec ID                    : 40
Duration                    : 15s 744ms
Bit rate mode               : Constant
Bit rate                    : 256 Kbps
Channel(s)                  : 2 channels
Channel positions           : Front: L R
Sampling rate               : 48.0 KHz
Frame rate                  : 46.875 fps (1024 spf)
Compression mode            : Lossy
Stream size                 : 492 KiB (1%)
Title                       : SoundHandle
Language                    : English
Encoded date                : UTC 2016-06-11 14:31:50
Tagged date                 : UTC 2016-06-11 14:31:50

我用来创建它的代码是:

describe('Unit tests', function () {
it("contains spec with an expectation", function() {
    service.getAllClients().then(function (res) {
        expect("hello world").toEqual("hello world");
        done();
    }).catch(function (err) {
        fail();
    });
});

我遵循了Android源代码(测试和应用程序)代码,以及我在github上找到的一些示例,因为camera2 API还没有很好地记录下来。

有什么明显的东西我做错了吗?或者,我是否只是在Mac上缺少使用Quicktime的编解码器以及在我的PC上使用Windows Media Player和VLC?我还没试过在Linux上播放这些文件,所以我不知道那里发生了什么。哦,如果我将mp4文件上传到photos.google.com,它们也可以完全正确地在那里播放。

谢谢! 标记

2 个答案:

答案 0 :(得分:7)

当我们开发基于Camera2 API的插件时,我的团队遇到了类似的问题,但它只影响了三星Galaxy S7(我们还有一个用于测试的S6没有出现这种行为)。

这个问题似乎是由三星相机固件中的一个错误造成的,当设备退出深度睡眠模式(Android 6.0 Marshmallow中的超低功耗模式)时触发了该问题。从深度睡眠恢复后,使用Camera2 MediaRecorder捕获和编码的任何视频的第一帧帧长度非常长 - 有时与视频本身的总持续时间一样长或更长。

因此,在播放时,在音频继续播放的同时显示第一帧这么长的持续时间。第一帧完成显示后,其余帧将正常播放。

我们发现其他人有类似问题discussing the issue on GitHub

  

问题是运行Marshmallow的某些设备存在深度睡眠问题。它看起来与CPU有关,因为Verizon上的S7没有问题,但AT& T上的S7确实存在问题。当我更新到Marshmallow时,我在S6 Verizon手机上看过这个。

     

要复制,请在连接USB时重启设备。运行示例。一切都应该没问题。然后,断开设备,让它进入深度睡眠状态(屏幕关闭,5分钟内没有移动),然后再试一次。一旦设备进入深度睡眠状态,就会出现此问题。

我们最终使用cybaker's proposed workaround;也就是说,创建视频文件时,请检查视频第一帧的持续时间。如果看起来不正确,请使用合理的帧持续时间重新编码视频:

DataSource channel = new FileDataSourceImpl(rawFile);
IsoFile isoFile = new IsoFile(channel);

List<TrackBox> trackBoxes = isoFile.getMovieBox().getBoxes(TrackBox.class);
boolean sampleError = false;
for (TrackBox trackBox : trackBoxes) {
    TimeToSampleBox.Entry firstEntry = trackBox.getMediaBox().getMediaInformationBox().getSampleTableBox().getTimeToSampleBox().getEntries().get(0);

    // Detect if first sample is a problem and fix it in isoFile
    // This is a hack. The audio deltas are 1024 for my files, and video deltas about 3000
    // 10000 seems sufficient since for 30 fps the normal delta is about 3000
    if(firstEntry.getDelta() > 10000) {
        sampleError = true;
        firstEntry.setDelta(3000);
    }
}

if(sampleError) {
    Movie movie = new Movie();
    for (TrackBox trackBox : trackBoxes) {
            movie.addTrack(new Mp4TrackImpl(channel.toString() + "[" + trackBox.getTrackHeaderBox().getTrackId() + "]" , trackBox));
    }
    movie.setMatrix(isoFile.getMovieBox().getMovieHeaderBox().getMatrix());
    Container out = new DefaultMp4Builder().build(movie);

    //delete file first!
    FileChannel fc = new RandomAccessFile(rawFile.getName(), "rw").getChannel();
    out.writeContainer(fc);
    fc.close();
    Log.d(TAG, "Finished correcting raw video");
}

希望这能指出你正确的方向!

答案 1 :(得分:0)

请注意,harper发布的上述代码需要这些依赖项:

compile 'com.googlecode.mp4parser:isoparser:1.1.22'