From: Peng Li Date: Tue, 8 May 2018 04:25:09 +0000 (+0800) Subject: running in background X-Git-Tag: v0.1.0~1 X-Git-Url: http://47.100.26.94:8080/?a=commitdiff_plain;h=a85b59e50709ca043c1464d3456dcd1abee84b8c;p=rtmpclient.git running in background --- diff --git a/app/src/main/java/ai/suanzi/rtmpclient/Ffmpeg.java b/app/src/main/java/ai/suanzi/rtmpclient/Ffmpeg.java index ef9063a..e4eb05c 100644 --- a/app/src/main/java/ai/suanzi/rtmpclient/Ffmpeg.java +++ b/app/src/main/java/ai/suanzi/rtmpclient/Ffmpeg.java @@ -27,4 +27,5 @@ public class Ffmpeg { public native int process(byte[] data); public native int play(Object surface, String fname); public native int push(Object surface); + public native int preview(Object surface); } diff --git a/app/src/main/java/ai/suanzi/rtmpclient/MainActivity.java b/app/src/main/java/ai/suanzi/rtmpclient/MainActivity.java index ca06f1f..cd42637 100644 --- a/app/src/main/java/ai/suanzi/rtmpclient/MainActivity.java +++ b/app/src/main/java/ai/suanzi/rtmpclient/MainActivity.java @@ -19,6 +19,7 @@ import java.io.IOException; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import android.content.Intent; @@ -82,21 +83,31 @@ public class MainActivity extends AppCompatActivity implements SurfaceHolder.Cal e.printStackTrace(); }*/ - final Button btn2 = findViewById(R.id.button2); + final Button btn2 = findViewById(R.id.button); btn2.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View view){ Log.e(TAG, "onclick2"); //ffmpeg.play(mHolder.getSurface(),"/storage/sdcard0/output.flv"); ffmpeg.push(mHolder.getSurface()); + //ffmpeg.preview(mHolder.getSurface()); } }); Log.e(TAG, "onclick2"); - //ffmpeg.play(mHolder.getSurface(),"/storage/emulated/0/Movies/output.flv"); - //ffmpeg.play(mHolder.getSurface(),"/data/local/tmp/big_buck_bunny_720p_10mb.mp4"); + /* + try { + Log.e(TAG, "Run command"); + Process sh = Runtime.getRuntime().exec(new String[]{"su", "-c", "chmod 666 /dev/video0"}); + sh.waitFor(); + }catch (Exception e){ + e.printStackTrace(); + }*/ + + + btn2.post(new Runnable(){ @@ -107,6 +118,12 @@ public class MainActivity extends AppCompatActivity implements SurfaceHolder.Cal }); + Intent i = new Intent(); + i.setAction(Intent.ACTION_MAIN); + i.addCategory(Intent.CATEGORY_HOME); + this.startActivity(i); + + } //SurfaceTexture st = new SurfaceTexture(0); diff --git a/app/src/main/jni/ai_suanzi_rtmpclient_Ffmpeg.cpp b/app/src/main/jni/ai_suanzi_rtmpclient_Ffmpeg.cpp index e87fab1..760a062 100644 --- a/app/src/main/jni/ai_suanzi_rtmpclient_Ffmpeg.cpp +++ b/app/src/main/jni/ai_suanzi_rtmpclient_Ffmpeg.cpp @@ -345,7 +345,7 @@ JNIEXPORT jint JNICALL Java_ai_suanzi_rtmpclient_Ffmpeg_play (JNIEnv *env, jobje // Get a pointer to the codec context for the video stream AVCodecContext * pCodecCtx = pFormatCtx->streams[videoStream]->codec; -LOGE("============= %d ========",__LINE__); + LOGE("============= %d ========",__LINE__); // Find the decoder for the video stream AVCodec * pCodec = avcodec_find_decoder(pCodecCtx->codec_id); if(pCodec==NULL) { @@ -496,7 +496,6 @@ JNIEXPORT jint JNICALL Java_ai_suanzi_rtmpclient_Ffmpeg_push (JNIEnv *env, jobje return -1; } - // avcodec_alloc_context3() AVCodecContext *pCodecCtx = pFormatCtx->streams[video_index]->codec; if(avcodec_open2(pCodecCtx, dec, NULL) <0){ LOGE( "eee"); @@ -505,9 +504,7 @@ JNIEXPORT jint JNICALL Java_ai_suanzi_rtmpclient_Ffmpeg_push (JNIEnv *env, jobje // Open Output - //const char* out_path = "./abc.flv"; const char* out_path = "rtmp://192.168.1.35:1935/myapp/peng2"; - // const char* out_path = "/storage/sdcard0/output222.flv"; AVFormatContext *ofmt_ctx; avformat_alloc_output_context2(&ofmt_ctx, NULL, "flv", out_path); @@ -648,4 +645,159 @@ JNIEXPORT jint JNICALL Java_ai_suanzi_rtmpclient_Ffmpeg_push (JNIEnv *env, jobje av_free(pFrameYUV); avcodec_close(pCodecCtx); avformat_close_input(&pFormatCtx); + return 0; +} + +JNIEXPORT jint JNICALL Java_ai_suanzi_rtmpclient_Ffmpeg_preview (JNIEnv *env, jobject obj, jobject surface){ + + LOGE("###### video preview #####"); + + av_register_all(); + avdevice_register_all(); + + + AVFormatContext * pFormatCtx = avformat_alloc_context(); + + + av_log_set_callback(custom_log); + + AVInputFormat *ifmt=av_find_input_format("video4linux2"); + LOGE("===%s===", ifmt->name); + if(avformat_open_input(&pFormatCtx,"/dev/video0",ifmt,NULL)!=0){ + LOGE("Couldn't open file:\n"); + return -1; // Couldn't open file + } + + // Retrieve stream information + if(avformat_find_stream_info(pFormatCtx, NULL)<0) { + LOGE("Couldn't find stream information."); + return -1; + } + + // Find the first video stream + int videoStream = -1, i; + for (i = 0; i < pFormatCtx->nb_streams; i++) { + if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO + && videoStream < 0) { + videoStream = i; + } + } + if(videoStream==-1) { + LOGE("Didn't find a video stream."); + return -1; // Didn't find a video stream + } + + // Get a pointer to the codec context for the video stream + AVCodecContext * pCodecCtx = pFormatCtx->streams[videoStream]->codec; + LOGE("============= %d ========",__LINE__); + // Find the decoder for the video stream + AVCodec * pCodec = avcodec_find_decoder(pCodecCtx->codec_id); + if(pCodec==NULL) { + LOGE("Codec not found."); + return -1; // Codec not found + } + + if(avcodec_open2(pCodecCtx, pCodec, NULL) < 0) { + LOGE("Could not open codec."); + return -1; // Could not open codec + } + + // 获取native window + ANativeWindow* nativeWindow = ANativeWindow_fromSurface(env, surface); + + // 获取视频宽高 + int videoWidth = pCodecCtx->width; + int videoHeight = pCodecCtx->height; + + // 设置native window的buffer大小,可自动拉伸 + ANativeWindow_setBuffersGeometry(nativeWindow, videoWidth, videoHeight, WINDOW_FORMAT_RGBA_8888); + ANativeWindow_Buffer windowBuffer; + + + LOGE("stream format:%s", pFormatCtx->iformat->name); + LOGE("duration :%lld", (pFormatCtx->duration) / 1000000); + LOGE("Width, Height:%d x %d", pCodecCtx->width, pCodecCtx->height); + LOGE("Decoder name:%s", pCodec->name); + + // Allocate video frame + AVFrame * pFrame = av_frame_alloc(); + + // 用于渲染 + AVFrame * pFrameRGBA = av_frame_alloc(); + if(pFrameRGBA == NULL || pFrame == NULL) { + LOGE("Could not allocate video frame."); + return -1; + } + + // Determine required buffer size and allocate buffer + int numBytes=av_image_get_buffer_size(AV_PIX_FMT_RGBA, pCodecCtx->width, pCodecCtx->height, 1); + uint8_t * buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t)); + av_image_fill_arrays(pFrameRGBA->data, pFrameRGBA->linesize, buffer, AV_PIX_FMT_RGBA, + pCodecCtx->width, pCodecCtx->height, 1); + + // 由于解码出来的帧格式不是RGBA的,在渲染之前需要进行格式转换 + struct SwsContext *sws_ctx = sws_getContext(pCodecCtx->width, + pCodecCtx->height, + pCodecCtx->pix_fmt, + pCodecCtx->width, + pCodecCtx->height, + AV_PIX_FMT_RGBA, + SWS_BILINEAR, + NULL, + NULL, + NULL); + + int frameFinished; + AVPacket packet; + while(av_read_frame(pFormatCtx, &packet)>=0) { + // Is this a packet from the video stream? + if(packet.stream_index==videoStream) { + + // Decode video frame + avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet); + + // 并不是decode一次就可解码出一帧 + if (frameFinished) { + + // lock native window buffer + ANativeWindow_lock(nativeWindow, &windowBuffer, 0); + + // 格式转换 + sws_scale(sws_ctx, (uint8_t const * const *)pFrame->data, + pFrame->linesize, 0, pCodecCtx->height, + pFrameRGBA->data, pFrameRGBA->linesize); + + // 获取stride + uint8_t * dst = (uint8_t*) windowBuffer.bits; + int dstStride = windowBuffer.stride * 4; + uint8_t * src = (uint8_t*) (pFrameRGBA->data[0]); + int srcStride = pFrameRGBA->linesize[0]; + + // 由于window的stride和帧的stride不同,因此需要逐行复制 + int h; + for (h = 0; h < videoHeight; h++) { + memcpy(dst + h * dstStride, src + h * srcStride, srcStride); + } + + ANativeWindow_unlockAndPost(nativeWindow); + } + + } + av_packet_unref(&packet); + } + + av_free(buffer); + av_free(pFrameRGBA); + + // Free the YUV frame + av_free(pFrame); + + // Close the codecs + avcodec_close(pCodecCtx); + + // Close the video file + avformat_close_input(&pFormatCtx); + + //env->ReleaseStringUTFChars(fname, file_name); + return 0; } \ No newline at end of file diff --git a/app/src/main/jni/ai_suanzi_rtmpclient_Ffmpeg.h b/app/src/main/jni/ai_suanzi_rtmpclient_Ffmpeg.h index 5b2becd..9752077 100644 --- a/app/src/main/jni/ai_suanzi_rtmpclient_Ffmpeg.h +++ b/app/src/main/jni/ai_suanzi_rtmpclient_Ffmpeg.h @@ -63,6 +63,14 @@ JNIEXPORT jint JNICALL Java_ai_suanzi_rtmpclient_Ffmpeg_play JNIEXPORT jint JNICALL Java_ai_suanzi_rtmpclient_Ffmpeg_push (JNIEnv *, jobject, jobject); +/* + * Class: ai_suanzi_rtmpclient_Ffmpeg + * Method: preview + * Signature: (Ljava/lang/Object;)I + */ +JNIEXPORT jint JNICALL Java_ai_suanzi_rtmpclient_Ffmpeg_preview + (JNIEnv *, jobject, jobject); + #ifdef __cplusplus } #endif diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 4353116..1d7d3c2 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -6,15 +6,6 @@ android:layout_height="match_parent" tools:context=".MainActivity"> - -