环境 WINDOW+Eclipse NDK+MinGW+NGINX 学习记录 直播原理(简单原理) 直播效果 客户端拉流 客户端开发 JNIEXPORT jstring JNICALL Java_com_example_androidtest_MainActivity_playVideo (JNIEnv* env, jobject obj, jstring url, jobject surface){ const char * jni_url = (*env)->GetStringUTFChars(env,url,JNI_FALSE); LOGE(“video url =%s”,jni_url); //使用ffmpeg第一个调用函数,注册解析器 解码器等 av_register_all(); LOGE(“av_register_all”); AVFormatContext *formatCtx = avformat_alloc_context(); LOGE(“avformat_alloc_context”); //打开对应的地址 if(avformat_open_input(&formatCtx,jni_url,NULL,NULL)!=0){ LOGE(“input error”); } //得到流信息 avformat_find_stream_info(formatCtx, NULL); LOGE(“video nb_streams =%d”,formatCtx->nb_streams); if(formatCtx->nb_streams<0){ LOGE(“not find stream”); return “”; } int video_index = -1; for(int i = 0;inb_streams;i++){ //从流信息中取得视频流 if(formatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO &&video_index < 0){ video_index = i; } } LOGE(“video_index=%d”,video_index); AVCodecContext * avCodecCtx = formatCtx->streams[video_index]->codec; LOGE(“avcodec_find_decoder”); //根据ID找到解码器实体 AVCodec * avCodec = avcodec_find_decoder(avCodecCtx->codec_id); if(avCodec==NULL){ LOGE(“codec not find”); } LOGE(“avcodec_open2”); //打开解码器 avcodec_open2(avCodecCtx, avCodec, NULL); //找到surface ANativeWindow * nativeWindow = ANativeWindow_fromSurface(env, surface); LOGE(“ANativeWindow_fromSurface”); //取到视频宽 int width = avCodecCtx->width; LOGE(“width=%d”,width); //取到视频高 int height = avCodecCtx->height; LOGE(“height=%d”,height); // 设置native window的buffer大小,可自动拉伸 ANativeWindow_setBuffersGeometry(nativeWindow, width, height,WINDOW_FORMAT_RGBA_8888); LOGE(“ANativeWindow_setBuffersGeometry”); ANativeWindow_Buffer windowBuffer; AVFrame * frame = av_frame_alloc(); LOGE(“av_frame_alloc”); AVFrame * format_frame = av_frame_alloc(); //计算buffer的大小 int numBytes = av_image_get_buffer_size(AV_PIX_FMT_RGBA, width, height,1); LOGE(“numBytes=%d”,numBytes); uint8_t * buffer = av_malloc(numBytes*(sizeof(uint8_t))); av_image_fill_arrays(format_frame->data,format_frame->linesize,buffer, AV_PIX_FMT_RGBA, width, height, 1); LOGE(“av_image_fill_arrays”); //转换格式 将源格式转换成RGBA struct SwsContext *sws_ctx = sws_getContext(width,height,avCodecCtx->pix_fmt,width,height, AV_PIX_FMT_RGBA,SWS_BILINEAR,NULL,NULL,NULL); LOGE(“sws_getContext”); AVPacket packet; int frameFinished; //读取数据 while(av_read_frame(formatCtx,&packet)>=0){ if(packet.stream_index==video_index){ avcodec_decode_video2(avCodecCtx,frame,&frameFinished,&packet); if(frameFinished){ // ANativeWindow_lock(nativeWindow,&windowBuffer,0); sws_scale(sws_ctx,(char *)frame->data,frame->linesize,0, height,format_frame->data,format_frame->linesize); uint8_t *dst = windowBuffer.bits; int dstStride = windowBuffer.stride*4; uint8_t src = (uint8_t)(format_frame->data[0]); int srcStride = format_frame->linesize[0]; for(int i =0;i