[原创 ]如何在Android平台实现H.264视频数据压制与传送
本帖最后由 error结构体 于 2014-10-28 16:51 编辑本帖子主要展示如何在Android平台实现对摄像头数据采集,再通过JNI调用ffmpeg库压制成H.264格式的视频数据,再通过简单UDP协议外发到WIN平台的简易例程,没有实现RTSP和考虑的效率,。实现步骤如下:
1、Android 摄像部分代码实现摄像数据采集。上传代码部分没有实现设定采集YUV数据的宽高。
@Override
public void onPreviewFrame(byte[] arg0, Camera arg1) {
// TODO Auto-generated method stub
if(arg0 != null)
{
int len = arg0.length;
Log.i("xinw","len:"+String.valueOf(len));
encodeprocess(arg0);
}
}
public boolean getIsPreviewCallback()
{
return ispreviewcallback;
}
public void setIsPreviewCallback(boolean flag)
{
ispreviewcallback = flag;
}android端界面效果如下:
2、定义JNI接口,实现对FFMPEG库的调用。JAVA部分:
static{
System.loadLibrary("postproc-53");
System.loadLibrary("avutil-54");
System.loadLibrary("avcodec-56");
System.loadLibrary("swresample-1");
System.loadLibrary("avformat-56");
System.loadLibrary("swscale-3");
System.loadLibrary("avfilter-5");
System.loadLibrary("avdevice-56");
System.loadLibrary("x264");
System.loadLibrary("ffmpeg_codec");
}
public native int encodeinit(String inputStr);
public native int encodeprocess(byte[] yuv420spArr);
PS:另外如何编译FFMPEG库和X264看我上一篇发的帖子:http://developer.t-firefly.com/thread-201-1-1.html
JNI的C语言的实现:
//static void video_encode_example(int i)
JNIEXPORT jint JNICALL Java_com_tchip_remotepushvideo_CameraPreview_encodeprocess(JNIEnv *env, jobject obj,jbyteArray yuvspArr)
{
jbyte *tmpHandle = (*env)->GetByteArrayElements(env,yuvspArr,NULL);
av_init_packet(&pkt);
pkt.data = NULL; // packet data will be allocated by the encoder
pkt.size = 0;
LOGD("ffmpeg cxx");
/* prepare a dummy image */
/* Y */
for (y = 0; y < c->height; y++) {
for (x = 0; x < c->width; x++) {
frame->data + x] = tmpHandle;
}
}
/* Cb and Cr */
for (y = 0; y < c->height/2; y++) {
for (x = 0; x < c->width/2; x++) {
frame->data + x] = tmpHandle;
frame->data + x] = tmpHandle;
}
}
//以上代码作用是将YUV420SP转为YUV420P caixx
frame->pts = i++;
/* encode the image */
ret = avcodec_encode_video2(c, &pkt, frame, &got_output);
if (ret < 0) {
//fprintf(stderr, "Error encoding frame\n");
//exit(1);
}
if (got_output) {
//printf("Write frame %3d (size=%5d)\n", i, pkt.size);
//printf("count:%d\n",g_h264q.size());
//fwrite(pkt.data, 1, pkt.size, f);
sendto(g_socket,pkt.data, pkt.size, 0, (struct sockaddr *)&g_addr, sizeof(g_addr));
av_free_packet(&pkt);
}
}
3、PC端实现对接收H.264数据的解码。效果如下:
其中代码部分主要是基于对ffmpeg中sample, decoding_encoding.c的改造。
PS:代码中的IP地址和数据数组宽高为了调试方便,都是绝对值,若要正常使用,请更改相关参数。
截取摄像头数据的YUV数组使用者要注意他们的大小,我用的一直罗技的免驱的摄像头,预览时显示是544*288的,但实际上YUV数组大小是1024*768的。 可做视频监控,好文呀。{:2_31:}
不知道流畅度如何。 有延时,没有去深究其中的原因。期待有网友的改善意见。 建议:用硬件编码,参考MediaCodec类。
用硬编就不用搞这么一大堆,是方便好多,效率也会好些。:lol 找到个硬解相关的帖子,http://blog.csdn.net/liuhongxiangm/article/details/17584303
MARK一下。:P 请问楼主怎么使用Android客户端啊 就是这个包, remotepushvideo.tar.gz ,要自己编译的。。。 楼主,我编译你的文件,跑步起来,报下列错误:
D:\Documents\xingyun\remotepushvideo\app\build\intermediates\ndk\debug\obj/local/arm64-v8a/objs/ffmpeg_codec/D_\Documents\xingyun\remotepushvideo\app\src\main\jni\ffmpeg_codec.o: In function `Java_com_tchip_codecvideo_CameraPreview_encodeinit':
D:\Documents\xingyun\remotepushvideo\app\build\intermediates\ndk\debug\obj/local/arm64-v8a/objs/ffmpeg_codec/D_\Documents\xingyun\remotepushvideo\app\src\main\jni\ffmpeg_codec.o: In function `Java_com_tchip_codecvideo_CameraPreview_encodeprocess':
D:\Documents\xingyun\remotepushvideo\app\src\main\jni\ffmpeg_codec.c
Error:(213) undefined reference to `av_register_all'
Error:(230) undefined reference to `avcodec_find_encoder'
Error:(236) undefined reference to `avcodec_alloc_context3'
Error:(262) undefined reference to `av_opt_set'
Error:(265) undefined reference to `avcodec_open2'
Error:(271) undefined reference to `av_frame_alloc'
Error:(282) undefined reference to `av_image_alloc'
Error:(294) undefined reference to `av_init_packet'
Error:(299) undefined reference to `__android_log_print'
Error:(325) undefined reference to `avcodec_encode_video2'
Error:(336) undefined reference to `av_free_packet'
Error:error: ld returned 1 exit status
make.exe: *** Error 1
Error:Execution failed for task ':app:compileDebugNdk'.
> com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException: Process 'command 'D:\Android\android-ndk-r10e\ndk-build.cmd'' finished with non-zero exit value 2
请问什么原因?