- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试从我的 Samsung Galaxy S6(支持 1920x1080,约 30 fps)上的后置摄像头(面对脸部的摄像头)录制视频。如果不需要,我不想使用任何表面进行预览,因为这只会在后台发生。
我似乎让它工作了,但输出文件无法以实际正确的方式播放。在我的 Windows 10 PC 上,Windows Media Player 将显示第一帧然后播放音频,VLC 不会显示任何帧。在我的手机上,录制的文件可以播放,但不能完全播放。它将保持第一帧 5-8 秒,然后在最后,剩余时间变为 0,显示的总时间发生变化,然后实际视频帧开始播放。在我的 Mac (10.9.5) 上,Quicktime 不会显示视频(虽然没有错误),但 Google Picasa 可以完美播放。我想在我的 PC 上试用 Picasa 看看它是否在那里工作,但我无法再下载 Google Picasa,因为已经日落了。
我尝试安装我找到的适用于 Windows 的编解码器包,但没有解决任何问题。 MediaInfo v0.7.85 报告有关该文件的信息:
GeneralComplete name : C:\...\1465655479915.mp4Format : MPEG-4Format profile : Base Media / Version 2Codec ID : mp42 (isom/mp42)File size : 32.2 MiBDuration : 15s 744msOverall bit rate : 17.1 MbpsEncoded date : UTC 2016-06-11 14:31:50Tagged date : UTC 2016-06-11 14:31:50com.android.version : 6.0.1VideoID : 1Format : AVCFormat/Info : Advanced Video CodecFormat profile : High@L4Format settings, CABAC : YesFormat settings, ReFrames : 1 frameFormat settings, GOP : M=1, N=30Codec ID : avc1Codec ID/Info : Advanced Video CodingDuration : 15s 627msBit rate : 16.2 MbpsWidth : 1 920 pixelsHeight : 1 080 pixelsDisplay aspect ratio : 16:9Frame rate mode : VariableFrame rate : 0.000 (0/1000) fpsMinimum frame rate : 0.000 fpsMaximum frame rate : 30.540 fpsColor space : YUVChroma subsampling : 4:2:0Bit depth : 8 bitsScan type : ProgressiveStream size : 0.00 Byte (0%)Source stream size : 31.7 MiB (98%)Title : VideoHandleLanguage : EnglishEncoded date : UTC 2016-06-11 14:31:50Tagged date : UTC 2016-06-11 14:31:50mdhd_Duration : 15627AudioID : 2Format : AACFormat/Info : Advanced Audio CodecFormat profile : LCCodec ID : 40Duration : 15s 744msBit rate mode : ConstantBit rate : 256 KbpsChannel(s) : 2 channelsChannel positions : Front: L RSampling rate : 48.0 KHzFrame rate : 46.875 fps (1024 spf)Compression mode : LossyStream size : 492 KiB (1%)Title : SoundHandleLanguage : EnglishEncoded date : UTC 2016-06-11 14:31:50Tagged date : UTC 2016-06-11 14:31:50
The code that I am using to create this is:
package invisiblevideorecorder;
import android.content.Context;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureRequest;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.view.Surface;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
/**
* @author Mark
* @since 6/10/2016
*/
public class InvisibleVideoRecorder {
private static final String TAG = "InvisibleVideoRecorder";
private final CameraCaptureSessionStateCallback cameraCaptureSessionStateCallback = new CameraCaptureSessionStateCallback();
private final CameraDeviceStateCallback cameraDeviceStateCallback = new CameraDeviceStateCallback();
private MediaRecorder mediaRecorder;
private CameraManager cameraManager;
private Context context;
private CameraDevice cameraDevice;
private HandlerThread handlerThread;
private Handler handler;
public InvisibleVideoRecorder(Context context) {
this.context = context;
handlerThread = new HandlerThread("camera");
handlerThread.start();
handler = new Handler(handlerThread.getLooper());
try {
mediaRecorder = new MediaRecorder();
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
final String filename = context.getExternalFilesDir(Environment.DIRECTORY_MOVIES).getAbsolutePath() + File.separator + System.currentTimeMillis() + ".mp4";
mediaRecorder.setOutputFile(filename);
Log.d(TAG, "start: " + filename);
// by using the profile, I don't think I need to do any of these manually:
// mediaRecorder.setVideoEncodingBitRate(16000000);
// mediaRecorder.setVideoFrameRate(30);
// mediaRecorder.setCaptureRate(30);
// mediaRecorder.setVideoSize(1920, 1080);
// mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);
// mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
// Log.d(TAG, "start: 1 " + CamcorderProfile.hasProfile(CameraMetadata.LENS_FACING_BACK, CamcorderProfile.QUALITY_1080P));
// true
// Log.d(TAG, "start: 2 " + CamcorderProfile.hasProfile(CameraMetadata.LENS_FACING_BACK, CamcorderProfile.QUALITY_HIGH_SPEED_1080P));
// false
// Log.d(TAG, "start: 3 " + CamcorderProfile.hasProfile(CameraMetadata.LENS_FACING_BACK, CamcorderProfile.QUALITY_HIGH));
// true
CamcorderProfile profile = CamcorderProfile.get(CameraMetadata.LENS_FACING_BACK, CamcorderProfile.QUALITY_1080P);
Log.d(TAG, "start: profile " + ToString.inspect(profile));
// start: 0 android.media.CamcorderProfile@114016694 {
// audioBitRate: 256000
// audioChannels: 2
// audioCodec: 3
// audioSampleRate: 48000
// duration: 30
// fileFormat: 2
// quality: 6
// videoBitRate: 17000000
// videoCodec: 2
// videoFrameHeight: 1080
// videoFrameRate: 30
// videoFrameWidth: 1920
// }
mediaRecorder.setOrientationHint(0);
mediaRecorder.setProfile(profile);
mediaRecorder.prepare();
} catch (IOException e) {
Log.d(TAG, "start: exception" + e.getMessage());
}
}
public void start() {
Log.d(TAG, "start: ");
cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
try {
cameraManager.openCamera(String.valueOf(CameraMetadata.LENS_FACING_BACK), cameraDeviceStateCallback, handler);
} catch (CameraAccessException | SecurityException e) {
Log.d(TAG, "start: exception " + e.getMessage());
}
}
public void stop() {
Log.d(TAG, "stop: ");
mediaRecorder.stop();
mediaRecorder.reset();
mediaRecorder.release();
cameraDevice.close();
try {
handlerThread.join();
} catch (InterruptedException e) {
}
}
private class CameraCaptureSessionStateCallback extends CameraCaptureSession.StateCallback {
private final static String TAG = "CamCaptSessionStCb";
@Override
public void onActive(CameraCaptureSession session) {
Log.d(TAG, "onActive: ");
super.onActive(session);
}
@Override
public void onClosed(CameraCaptureSession session) {
Log.d(TAG, "onClosed: ");
super.onClosed(session);
}
@Override
public void onConfigured(CameraCaptureSession session) {
Log.d(TAG, "onConfigured: ");
}
@Override
public void onConfigureFailed(CameraCaptureSession session) {
Log.d(TAG, "onConfigureFailed: ");
}
@Override
public void onReady(CameraCaptureSession session) {
Log.d(TAG, "onReady: ");
super.onReady(session);
try {
CaptureRequest.Builder builder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
builder.addTarget(mediaRecorder.getSurface());
CaptureRequest request = builder.build();
session.setRepeatingRequest(request, null, handler);
mediaRecorder.start();
} catch (CameraAccessException e) {
Log.d(TAG, "onConfigured: " + e.getMessage());
}
}
@Override
public void onSurfacePrepared(CameraCaptureSession session, Surface surface) {
Log.d(TAG, "onSurfacePrepared: ");
super.onSurfacePrepared(session, surface);
}
}
private class CameraDeviceStateCallback extends CameraDevice.StateCallback {
private final static String TAG = "CamDeviceStateCb";
@Override
public void onClosed(CameraDevice camera) {
Log.d(TAG, "onClosed: ");
super.onClosed(camera);
}
@Override
public void onDisconnected(CameraDevice camera) {
Log.d(TAG, "onDisconnected: ");
}
@Override
public void onError(CameraDevice camera, int error) {
Log.d(TAG, "onError: ");
}
@Override
public void onOpened(CameraDevice camera) {
Log.d(TAG, "onOpened: ");
cameraDevice = camera;
try {
camera.createCaptureSession(Arrays.asList(mediaRecorder.getSurface()), cameraCaptureSessionStateCallback, handler);
} catch (CameraAccessException e) {
Log.d(TAG, "onOpened: " + e.getMessage());
}
}
}
}
我遵循了 Android 源代码(测试和应用程序)以及我在 github 上找到的几个示例,以解决这个问题,因为 camera2 API 还没有很好的文档记录。
有什么明显的地方我做错了吗?或者,我是否只是在我的 Mac 上缺少用于 Quicktime 的编解码器以及在我的 PC 上用于 Windows Media Player 和 VLC 的编解码器?我还没有尝试在 Linux 上播放这些文件,所以我不知道那里会发生什么。哦,如果我将 mp4 文件上传到 photos.google.com,它们也可以在那里完全正确地播放。
谢谢!标记
最佳答案
我的团队在开发基于 Camera2 API 的插件时遇到了类似的问题,但它只影响了 Samsung Galaxy S7(我们还有用于测试的 S6 没有出现此行为)。
该问题似乎是由三星相机固件中的错误引起的,并在设备退出深度 sleep (Android 6.0 Marshmallow 中的超低功耗模式)时触发。从深度 sleep 中恢复后,使用 Camera2 MediaRecorder 捕获和编码的任何视频的第一帧都具有非常长的帧持续时间 - 有时与视频本身的总持续时间一样长或更长。
因此,在播放时,第一帧会显示这么长时间,同时音频会继续播放。第一帧显示完毕后,其余帧将正常播放。
我们发现其他人也有类似的问题discussing the issue on GitHub
The issue is a deep sleep problem on some devices running Marshmallow. It appears to be CPU related as an S7 on Verizon doesn't have the issue, but an S7 on AT&T does have the issue. I've seen this on an S6 Verizon phone when it updated to Marshmallow.
In order to replicate, reboot a device while connected to USB. Run the sample. All should be ok. Then, disconnect the device, let it go into deep sleep (screen off, no movement for 5? minutes), and try again. The issue will appear once the device has gone into deep sleep.
我们最终使用了 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");
}
希望这能为您指明正确的方向!
关于video - Android : mp4 output file not fully playable 上没有预览的 Camera2 视频录制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37767511/
我正在用 C 语言实现一个带有输入和输出重定向的 shell。我可以成功进行输入重定向,但输出重定向不起作用。例如,如果我执行 ls > out.txt,则 out.txt 包含文本“out.txt”
我正在处理创建 AWS API 网关。我正在尝试创建 CloudWatch Log 组并将其命名 API-Gateway-Execution-Logs_${restApiId}/${stageName
我正在修改原作者使用数组构建网页的一些代码: $output[]=$stuff_from_database; $output[]='more stuff'; // etc echo join(
我只想知道它们之间的区别: sort < output 和 sort output 在 Linux 中。它是如何工作的? 最佳答案 这已经在 unix.stackexchange 上讨论过:Perfo
我正在生成外部控制台应用程序并使用异步输出重定向。 as shown in this SO post 我的问题是,在我收到 OutputDataReceived 事件通知之前,生成的进程似乎需要产生一
在 Udemy 上开设类(class)时,我们一直允许使用组件类中的 @Input() 装饰器向组件传递数据。 在阅读 ngBook-2 时,我发现还有另一种方法,即在 @Component 装饰器中
考虑一个 Linux 服务器,它在您的用户的 .bash_profile 中有以下行: echo "Hello world" 因此,每次您通过 ssh 进入它时,您都会看到 Hello world 现
public static void main(String[] args) { String input = new String(JOptionPane.showInputDialog("
我正在使用 MSVS 2008 中的 FFTW3 库对某些数据执行 r2c DFT (n=128)。我已经发现只使用了真实数据 DFT 输出的前半部分……如果我查看我的输出,这似乎是正确的: 0-64
我制作了一个 C 程序,可以从二进制文件中打印出很多值。我相信程序完成它的功能并在它实际显示它吐出的值之前结束。因此,结果我得到了一个可爱的 RUN SUCCESSFUL(总时间:198ms) 突然出
在 hadoop 作业计数器中,“映射输出具体化字节”与“映射输出字节”之间有什么区别?当我禁用映射输出压缩时我没有看到前者所以我猜它是真正的输出字节(压缩)而后者是未压缩的字节? 最佳答案 我认为你
有很多 Stack Overflow 文章与此相关,但没有直接的答案。 这条命令会输出一堆单词 OutputVariable.exe %FILEPATH% 输出: Mary had a little
互联网上的许多文章都使用“标准输入/输出/错误流”术语好像每个术语都与使用的“标准输入/输出/错误设备”术语具有相同的含义在其他文章上。例如,很多文章说标准输出流默认是监视器,但可以重定向到文件、打印
我在 Keras 中使用一些 tensorflow 函数(reduce_sum 和 l2_normalize)在最后一层构建模型时遇到了这个问题。我已经搜索了一个解决方案,但所有这些都与“Keras
我有来自 API 的自定义输出,我想将其格式化为带有一些颜色值的字符串。 最佳答案 输出 channel 可以用 TmLanguage grammar 着色. Output Colorizer扩展扩展
我正在寻找一种方法来查看虚拟机创建过程中发生的情况,因为我使用复杂的集群配置并测试其是否正常工作,我需要能够查看输出,在某些情况下我是不是因为敏感。这与运行remote-exec选项有关 module
当谷歌搜索此错误时没有看到任何相关结果,所以我想发布它。 stack build Building all executables for `gitchapter' once. After a suc
假设module_a里面有register_a,它需要链接到module_b。 register_a 是否应该单独声明并分配给 module_a 的输出: reg register_a; assign
我正在寻找一种方法来查看虚拟机创建过程中发生的情况,因为我使用复杂的集群配置并测试其是否正常工作,我需要能够查看输出,在某些情况下我是不是因为敏感。这与运行remote-exec选项有关 module
输入文件如下 eno::ename::dept::sal 101::emp1::comp1::2800000 201::emp2::comp2::2800000 301::emp3::comp3::3
我是一名优秀的程序员,十分优秀!