X-Git-Url: http://47.100.26.94:8080/?a=blobdiff_plain;f=app%2Fsrc%2Fmain%2Fjni%2Fai_suanzi_rtmpclient_Ffmpeg.cpp;fp=app%2Fsrc%2Fmain%2Fjni%2Fai_suanzi_rtmpclient_Ffmpeg.cpp;h=7b16b491bfe7ab36d8c96adbc5be2687d27d0c15;hb=6d410bf5e67288660c675d0aa76891eb8367e7cc;hp=a901482be765b2c8aaaf555682d66f6157cfcfc6;hpb=791f24bb2d6f4faa5ff14e29c518ca078e9743eb;p=rtmpclient.git diff --git a/app/src/main/jni/ai_suanzi_rtmpclient_Ffmpeg.cpp b/app/src/main/jni/ai_suanzi_rtmpclient_Ffmpeg.cpp index a901482..7b16b49 100644 --- a/app/src/main/jni/ai_suanzi_rtmpclient_Ffmpeg.cpp +++ b/app/src/main/jni/ai_suanzi_rtmpclient_Ffmpeg.cpp @@ -12,6 +12,7 @@ extern "C" { #include "libswscale/swscale.h" #include "libavutil/imgutils.h" #include "libavutil/time.h" + #include "libavdevice/avdevice.h" } int64_t start_time; @@ -23,15 +24,48 @@ AVPacket enc_pkt; AVFrame *pFrameYUV; +void custom_log(void *ptr, int level, const char* fmt, va_list vl){ + + //To TXT file + + /*FILE *fp=fopen("/storage/emulated/0/av_log.txt","a+"); + if(fp){ + vfprintf(fp,fmt,vl); + fflush(fp); + fclose(fp); + } */ + + + //To Logcat + LOGE(fmt, vl); +} + + int framecnt = 0; int yuv_width; int yuv_height; int y_length; int uv_length; + + JNIEXPORT jstring JNICALL Java_ai_suanzi_rtmpclient_Ffmpeg_getVersion (JNIEnv *env, jobject obj) { jint v = avformat_version(); LOGE("######### Ffmpeg JNI version i= %d", v); + + + /*AVFormatContext *pFormatCtx = avformat_alloc_context(); + avdevice_register_all(); + 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 input stream.\n"); + return env->NewStringUTF("===== error ======="); + + //return -1; + }*/ + return env->NewStringUTF("====== Ffmpeg call ======="); } @@ -39,11 +73,12 @@ 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 = "rtmp://192.168.1.35:1935/myapp/suanzi"; + const char* out_path = "/storage/sdcard0/output.flv"; - LOGE("Ffmpeg init, width=%d, heigh=%d", width, height); + LOGE("Ffmpeg init, width=%d, heigh=%d", width, height); yuv_width=width; yuv_height=height; @@ -227,6 +262,178 @@ JNIEXPORT jint JNICALL Java_ai_suanzi_rtmpclient_Ffmpeg_process (JNIEnv *env, jo return 0; } -JNIEXPORT jint JNICALL Java_ai_suanzi_rtmpclient_Ffmpeg_play (JNIEnv *env, jobject obj, jobject obj2, jstring fname){ +JNIEXPORT jint JNICALL Java_ai_suanzi_rtmpclient_Ffmpeg_play (JNIEnv *env, jobject obj, jobject surface, jstring fname){ + + + + + + LOGE("###### video play #####"); + // char * file_name = "/storage/emulated/0/Movies/big_buck_bunny_720p_10mb.mp4"; + const char * file_name = env->GetStringUTFChars(fname, 0); + + 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 + } + + +/////////// + +/* + // Open video file + if(avformat_open_input(&pFormatCtx, file_name, NULL, NULL)!=0) { + + LOGE("Couldn't open file:%s\n", file_name); + 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; + + if(avcodec_open2(pCodecCtx, pCodec, NULL)<0) { + LOGE("Could not open codec."); + return -1; // Could not open codec + } + + 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