背景:
两天来,我一直在努力实现一个像Vine一样的录像机。首先,我试了MediaRecorder。但我需要的视频可能是由小视频剪辑组成的。此类不能用于录制短时视频剪辑。然后我找到了MediaCodec、FFmpeg和JavaCV。FFmpeg和JavaCV可以解决这个问题。但是我必须用许多库文件来编译我的项目。它将生成一个非常大的APK文件。所以我更喜欢用MediaCodec实现它,尽管这个类只能在Android4.1之后使用。90%的用户会满意。
输入#0,h264,来自“test.mp4”:持续时间:n/a,比特率:n/a流#0:0:视频:h264(基线),yuv420p,640x480,25 fps,25 tbr,1200k tbn,50 tbc
我对H.264编码的机制不是很了解。
代码:
public class AvcEncoder {
private static String TAG = AvcEncoder.class.getSimpleName();
private MediaCodec mediaCodec;
private BufferedOutputStream outputStream;
private int mWidth, mHeight;
private byte[] mDestData;
public AvcEncoder(int w, int h) {
mWidth = w;
mHeight = h;
Log.d(TAG, "Thread Id: " + Thread.currentThread().getId());
File f = new File("/sdcard/videos/test.mp4");
try {
outputStream = new BufferedOutputStream(new FileOutputStream(f));
Log.i("AvcEncoder", "outputStream initialized");
} catch (Exception e) {
e.printStackTrace();
}
try {
mediaCodec = MediaCodec.createEncoderByType("video/avc");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", w,
h);
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 2000000);
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 15);
// mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,
// MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar);
mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,
MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar);
mDestData = new byte[w * h
* ImageFormat.getBitsPerPixel(ImageFormat.YV12) / 8];
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5);
mediaCodec.configure(mediaFormat, null, null,
MediaCodec.CONFIGURE_FLAG_ENCODE);
mediaCodec.start();
}
public void close() {
try {
mediaCodec.stop();
mediaCodec.release();
mediaCodec = null;
// outputStream.flush();
outputStream.close();
} catch (IOException e) {
}
}
public void offerEncoder(byte[] input) {
try {
CameraUtils.transYV12toYUV420Planar(input, mDestData, mWidth,
mHeight);
ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers();
int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);
if (inputBufferIndex >= 0) {
ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
inputBuffer.clear();
inputBuffer.put(mDestData);
mediaCodec.queueInputBuffer(inputBufferIndex, 0,
mDestData.length, 0, 0);
}
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo,
0);
while (outputBufferIndex >= 0) {
ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
byte[] outData = new byte[bufferInfo.size];
outputBuffer.get(outData);
try {
outputStream.write(outData, 0, outData.length);
} catch (Exception e) {
Log.d("AvcEncoder", "Outputstream write failed");
e.printStackTrace();
}
// Log.i("AvcEncoder", outData.length + " bytes written");
mediaCodec.releaseOutputBuffer(outputBufferIndex, false);
outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo,
0);
}
} catch (Throwable t) {
t.printStackTrace();
}
}
}
private void startPreview() {
if (mCamera == null) {
return;
}
try {
mCamera.setPreviewDisplay(mSurfaceView.getHolder());
Parameters p = mCamera.getParameters();
Size s = p.getPreviewSize();
int len = s.width * s.height
* ImageFormat.getBitsPerPixel(p.getPreviewFormat()) / 8;
mAvcEncoder = new AvcEncoder(s.width, s.height);
mCamera.addCallbackBuffer(new byte[len]);
mCamera.setPreviewCallbackWithBuffer(new PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
mAvcEncoder.offerEncoder(data);
mCamera.addCallbackBuffer(data);
}
});
mCamera.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
}
松开相机时关闭:
private void releaseCamera() {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
if (mAvcEncoder != null) {
mAvcEncoder.close();
}
}
您正在保存一个原始的H.264流。您应该将其转换为.mp4格式。最简单的方法是使用MediaMuxer类(API18+)。
你可以在bigflake上找到一个简单的例子,在Grafika中找到更完整的例子。
您将需要为每个帧提供演示时间戳。您可以根据所需的帧率生成它们(如bigflake示例),也可以从源获取它们(如Grafika中的相机输入示例)。
在您的特定情况下,我将注意到,示例代码试图指定输入格式,但这没有效果--AVC编解码器定义了它接受的输入格式,而应用程序必须查询它。您可能会发现编码视频中的颜色当前是错误的,因为摄像机和MediaCodec没有任何共同的颜色格式(参见颜色交换代码的答案)。
我正在尝试使用MediaCodec和MediaMuxer对来自相机的视频和来自麦克风的音频进行编码。我在录制时使用OpenGL在图像上覆盖文本。 我以这些课程为例: http://bigflake.com/mediacodec/CameraToMpegTest.java.txt https://github.com/OnlyInAmerica/HWEncoderExperiments/blob/m
我正在使用Java API实现一个解码器,用于解码实时H.264远程流。我正在使用回调()从本机层接收H.264编码数据,并在的上解码和呈现。我的实现已经完成(使用回调、解码和呈现等方式检索编码流)。下面是我的解码器类: 现在的问题是-流正在解码和呈现在表面,但视频不清楚。看起来像是框架被打破了,场景被扭曲了/脏了。移动是破碎的和方形的碎片到处(我真的很抱歉,因为我没有截图现在)。 关于我的流-它
我正在开发一个通过RTP接收H264编码数据的应用程序,但我无法让Android的MediaCodec输出任何内容。我正在按照https://stackoverflow.com/a/7668578/10788248对RTP数据包进行解包 在编码帧被重新组装后,我将它们输入到出列的输入缓冲区中。 当我对输入缓冲区进行排队时,我不会得到任何错误,但是解码器的回调从来不会调用onOutputBuffer
我正在尝试写一个基本的原始AAC数据到一个文件,希望我可以使用mp4parser封装它与一个视频轨道。为此,我需要将任何给定的音频文件编码为该格式。MediaCodec API从API16开始就很容易获得,所以我决定使用它来进行编解码操作。 我不确定为什么没有很多资源可以在线上关于这一点,可能是由于相关的复杂性。不过,我已经了解到基本的方法应该是: 通过MediaExtractor获取样本数据->
问题内容: 我遵循了一些有关结合JavaFX与Swing(JFrame)来播放视频的教程,但是我得到的只是一个黑屏,该视频应该没有任何实际的内容播放,也没有报错。 我在这里做错什么,为什么不播放视频? 我尝试了几个.flv视频,但都不会开始播放(当我在浏览器中打开它们时,它们会播放) 我在装有K-lite完整编解码器包的Windows 8.1 N Pro上运行jre7和jdk1.7.0_45 编辑
每当我加载html文件时,它都会给我一个错误 每当我按下播放按钮时,就会出现以下错误 我能够加载任何远程视频并运行,但问题是当我从资产文件夹代码加载本地视频以加载文件并设置web视图时 干杯,Saurav