欢迎使用CSDN-markdown编辑器

来源:互联网 发布:模糊图片修复软件 编辑:程序博客网 时间:2024/06/05 09:17
             **Android直播介绍**

环境
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