capture video on usb camera and encode with libx264
authorPeng Li <seudut@gmail.com>
Tue, 8 May 2018 02:59:55 +0000 (10:59 +0800)
committerPeng Li <seudut@gmail.com>
Tue, 8 May 2018 02:59:55 +0000 (10:59 +0800)
app/src/main/AndroidManifest.xml
app/src/main/java/ai/suanzi/rtmpclient/Ffmpeg.java
app/src/main/java/ai/suanzi/rtmpclient/MainActivity.java
app/src/main/jni/ai_suanzi_rtmpclient_Ffmpeg.cpp
app/src/main/jni/ai_suanzi_rtmpclient_Ffmpeg.h

index e954746..19ba5b3 100644 (file)
@@ -22,5 +22,4 @@
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.INTERNET" />
-
 </manifest>
\ No newline at end of file
index 2f7273d..ef9063a 100644 (file)
@@ -26,4 +26,5 @@ public class Ffmpeg {
     public native int close();
     public native int process(byte[] data);
     public native int play(Object surface, String fname);
+    public native int push(Object surface);
 }
index abef9c8..ca06f1f 100644 (file)
@@ -87,7 +87,8 @@ public class MainActivity extends AppCompatActivity implements SurfaceHolder.Cal
             @Override
             public void onClick(View view){
                 Log.e(TAG, "onclick2");
-                ffmpeg.play(mHolder.getSurface(),"/storage/sdcard0/output.flv");
+                //ffmpeg.play(mHolder.getSurface(),"/storage/sdcard0/output.flv");
+                ffmpeg.push(mHolder.getSurface());
 
             }
 
index 7b16b49..e87fab1 100644 (file)
@@ -37,7 +37,31 @@ void custom_log(void *ptr, int level, const char* fmt, va_list vl){
 
 
     //To Logcat
-    LOGE(fmt, vl);
+   // LOGE(fmt, vl);
+
+
+        static int print_prefix = 1;
+        static int count;
+        static char prev[1024];
+        char line[1024];
+        static int is_atty;
+
+        av_log_format_line(ptr, level, fmt, vl, line, sizeof(line), &print_prefix);
+
+        strcpy(prev, line);
+        //sanitize((uint8_t *)line);
+
+        if (level <= AV_LOG_WARNING)
+        {
+            LOGE("%s", line);
+        }
+        else
+        {
+            LOGE("%s", line);
+        }
+
+
+
 }
 
 
@@ -73,8 +97,8 @@ JNIEXPORT jint JNICALL Java_ai_suanzi_rtmpclient_Ffmpeg_init (JNIEnv *env, jobje
 
        //const char* out_path = "/storage/emulated/0/Movies/output.flv";
 
-    //const char* out_path = "rtmp://192.168.1.35:1935/myapp/suanzi";
-     const char* out_path = "/storage/sdcard0/output.flv";
+    const char* out_path = "rtmp://192.168.1.35:1935/myapp/suanzi";
+    // const char* out_path = "/storage/sdcard0/output.flv";
 
 
 
@@ -436,4 +460,192 @@ LOGE("============= %d ========",__LINE__);
 
      env->ReleaseStringUTFChars(fname, file_name);
     return 0;
+}
+
+JNIEXPORT jint JNICALL Java_ai_suanzi_rtmpclient_Ffmpeg_push (JNIEnv *env, jobject obj, jobject surface) {
+
+    av_log_set_level(AV_LOG_TRACE);
+    av_register_all();
+    avformat_network_init();
+    avdevice_register_all();
+
+    LOGE("====push=====");
+    av_log_set_callback(custom_log);
+
+    int ret = 0;
+    /// Open Input
+    AVFormatContext *pFormatCtx = avformat_alloc_context();
+
+    AVInputFormat *ifmt = av_find_input_format("video4linux2");
+    if(avformat_open_input(&pFormatCtx, "/dev/video0", ifmt, NULL) != 0) {
+        LOGE("could not open file11");
+        return -1;
+    }
+
+    if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
+        LOGE( "could not find stream info");
+        return -1;
+    }
+
+    av_dump_format(pFormatCtx, 0, "0", 0);
+
+    AVCodec *dec;
+    int video_index = -1;
+    if((video_index = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, &dec, 0)) < 0){
+        LOGE( "error");
+        return -1;
+    }
+
+    // avcodec_alloc_context3()
+    AVCodecContext *pCodecCtx = pFormatCtx->streams[video_index]->codec;
+    if(avcodec_open2(pCodecCtx, dec, NULL) <0){
+        LOGE( "eee");
+        return -1;
+    }
+
+
+    // 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);
+    AVCodec *oDec = avcodec_find_encoder(AV_CODEC_ID_H264);
+    if (!oDec) {
+        LOGE("Can not find endoder");
+        return -1;
+    }
+
+    AVCodecContext *oCodecCtx = avcodec_alloc_context3(oDec);
+    oCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
+    oCodecCtx->width = pCodecCtx->width;
+    oCodecCtx->height = pCodecCtx->height;
+    oCodecCtx->time_base.num = 1;
+    oCodecCtx->time_base.den = 30;
+    oCodecCtx->bit_rate = 800000;
+    oCodecCtx->gop_size = 300;
+    if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
+        oCodecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER;
+    oCodecCtx->qmin = 10;
+    oCodecCtx->qmax = 51;
+    oCodecCtx->max_b_frames = 3;
+
+    AVDictionary *params = 0;
+    av_dict_set(&params, "preset", "ultrafast", 0);
+    av_dict_set(&params, "tune", "zerolatency", 0);
+
+    if (avcodec_open2(oCodecCtx, oDec, &params) < 0){
+        LOGE("Failed to open encoder");
+        return -1;
+    }
+
+    AVStream *videoStream = avformat_new_stream(ofmt_ctx, oDec);
+    if (videoStream == NULL){
+        return -1;
+    }
+
+    videoStream->time_base.num = 1;
+    videoStream->time_base.den = 30;
+    videoStream->codec = oCodecCtx;
+
+    if((ret = avio_open(&ofmt_ctx->pb, out_path, AVIO_FLAG_READ_WRITE)) < 0){
+        LOGE("Failed open out file22 erro=%d, ==%s==", ret, av_err2str(ret) );
+        //LOGE("Failed open out file22 erro=%d", ret);
+        return -1;
+    }
+
+    avformat_write_header(ofmt_ctx, NULL);
+    /////////////
+
+
+
+
+    //
+    AVFrame *pFrame, *pFrameYUV;
+    pFrame = av_frame_alloc();
+    pFrameYUV = av_frame_alloc();
+
+    int num_bytes = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height, 1);
+    uint8_t *buffer = (uint8_t *)av_malloc(num_bytes * sizeof(uint8_t));
+    av_image_fill_arrays(pFrameYUV->data, pFrameYUV->linesize, buffer, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height, 1);
+
+    pFrameYUV->format = AV_PIX_FMT_YUV420P;
+    pFrameYUV->width = pCodecCtx->width;
+    pFrameYUV->height = pCodecCtx->height;
+
+    struct SwsContext *img_convert_ctx;
+    img_convert_ctx = sws_getContext(pCodecCtx->width,
+                              pCodecCtx->height,
+                              pCodecCtx->pix_fmt,
+                              pCodecCtx->width,
+                              pCodecCtx->height,
+                              AV_PIX_FMT_YUV420P,
+                              SWS_BICUBIC,
+                              NULL, NULL, NULL);
+
+    AVPacket *packet = (AVPacket *)av_malloc(sizeof(AVPacket));
+    int got_picture = 0;
+
+    AVPacket enc_pkt ;
+
+    int64_t framecnt = 0;
+
+    while(av_read_frame(pFormatCtx, packet) >= 0){
+        if (packet->stream_index == video_index){
+            ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
+            if (ret < 0){
+                LOGE("Decode Error.");
+                return -1;
+            }
+            if (got_picture){
+                sws_scale(img_convert_ctx, (const unsigned char* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);
+
+                enc_pkt.data = NULL;
+                enc_pkt.size = 0;
+                av_init_packet(&enc_pkt);
+                int enc_got_frame = 0;
+                ret = avcodec_encode_video2(oCodecCtx, &enc_pkt, pFrameYUV, &enc_got_frame);
+                if (enc_got_frame == 1){
+
+                           framecnt++;
+                    enc_pkt.stream_index = videoStream->index;
+
+                    // write PTS
+                    AVRational time_base = ofmt_ctx->streams[0]->time_base;
+                    AVRational r_framerate1 = {60, 2};
+                    AVRational time_base_q = {1, AV_TIME_BASE};
+
+                           int64_t calc_duration = (double)(AV_TIME_BASE)*(1 / av_q2d(r_framerate1));  //内部时间戳
+                    enc_pkt.pts = av_rescale_q(framecnt*calc_duration, time_base_q, time_base);
+                    enc_pkt.dts = enc_pkt.pts;
+                    enc_pkt.duration = av_rescale_q(calc_duration, time_base_q, time_base); //(double)(calc_duration)*(double)(av_q2d(time_base_q)) / (double)(av_q2d(time_base));
+                    enc_pkt.pos = -1;
+
+                    int64_t pts_time = av_rescale_q(enc_pkt.dts, time_base, time_base_q);
+
+                }
+
+
+                ret = av_interleaved_write_frame(ofmt_ctx, &enc_pkt);
+                //av_frame_free(&pFrameYUV);
+                //av_packet_unref(packet);
+
+                //av_free_packet(&enc_pkt);
+
+                /*
+                int y_size = pCodecCtx->width * pCodecCtx->height;
+                fwrite(pFrameYUV->data[0], 1, y_size, fp);      // Y
+                fwrite(pFrameYUV->data[1], 1, y_size / 4, fp);  // U
+                fwrite(pFrameYUV->data[2], 1, y_size / 4, fp);  // V
+                */
+            }
+        }
+        av_packet_unref(packet);
+    }
+
+    sws_freeContext(img_convert_ctx);
+    av_free(pFrameYUV);
+    avcodec_close(pCodecCtx);
+    avformat_close_input(&pFormatCtx);
 }
\ No newline at end of file
index 6615073..5b2becd 100644 (file)
@@ -55,6 +55,14 @@ JNIEXPORT jint JNICALL Java_ai_suanzi_rtmpclient_Ffmpeg_process
 JNIEXPORT jint JNICALL Java_ai_suanzi_rtmpclient_Ffmpeg_play
   (JNIEnv *, jobject, jobject, jstring);
 
+/*
+ * Class:     ai_suanzi_rtmpclient_Ffmpeg
+ * Method:    push
+ * Signature: (Ljava/lang/Object;)I
+ */
+JNIEXPORT jint JNICALL Java_ai_suanzi_rtmpclient_Ffmpeg_push
+  (JNIEnv *, jobject, jobject);
+
 #ifdef __cplusplus
 }
 #endif