zoukankan      html  css  js  c++  java
  • Android本地视频播放器开发--视频解码

    在上一章Android本地视频播放器开发--SDL编译编译中编译出sdl的支持库,当时我们使用的2.0,但是有些api被更改了,所以在以下的使用者中我们使用SDL1.3的库,这个库我会传上源码以及编译出的库,接下来这张我们使用ffmpeg解码视频文件中的视频帧同时使用SDL去显示。

    1、Decodec_Video.c 这是我视频解码的文件,其中内容如下:

    #include <stdio.h>
    #include <android/log.h>
    
    #ifdef __MINGW32__
    #undef main /* Prevents SDL from overriding main() */
    #endif
    
    #include "../SDL/include/SDL.h"
    #include "../SDL/include/SDL_thread.h"
    
    #include "VideoPlayerDecode.h"
    #include "../ffmpeg/libavutil/avutil.h"
    #include "../ffmpeg/libavcodec/avcodec.h"
    #include "../ffmpeg/libavformat/avformat.h"
    #include "../ffmpeg/libswscale/swscale.h"
    
    AVFormatContext *pFormatCtx;
    int             i, videoStream;
    AVCodecContext  *pCodecCtx;
    AVCodec         *pCodec;
    AVFrame         *pFrame;
    AVPacket        packet;
    int             frameFinished;
    float           aspect_ratio;
    
    static struct SwsContext *img_convert_ctx;
    SDL_Surface     *screen;
    SDL_Overlay	*bmp;
    SDL_Rect        rect;
    SDL_Event       event;
    
    
    JNIEXPORT jint JNICALL Java_com_zhangjie_graduation_videopalyer_jni_VideoPlayerDecode_VideoPlayer
    (JNIEnv *env, jclass clz, jstring fileName)
    {
    	const char* local_title = (*env)->GetStringUTFChars(env, fileName, NULL);
    	av_register_all();//注册所有支持的文件格式以及编解码器
    	if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
    		fprintf(stderr, "Could not initialize SDL - %s
    ", SDL_GetError());
    		exit(1);
    	}
    	if(avformat_open_input(&pFormatCtx, local_title, NULL, NULL) != 0)
                    return -1;
    	if(avformat_find_stream_info(pFormatCtx, NULL) < 0)
                    return -1;
    	av_dump_format(pFormatCtx, -1, local_title, 0);
    	videoStream=-1;
    	for(i=0; i<pFormatCtx->nb_streams; i++)
    		if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO) {
    			videoStream=i;
    			break;
    		}
    	if(videoStream==-1)
    		return -1; // Didn't find a video stream
    	// Get a pointer to the codec context for the video stream
    	pCodecCtx=pFormatCtx->streams[videoStream]->codec;
    
    	// Find the decoder for the video stream
    	pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
    	if(pCodec==NULL) {
    		fprintf(stderr, "Unsupported codec!
    ");
    		return -1; // Codec not found
    	}
    	if(avcodec_open2(pCodecCtx, pCodec, NULL) < 0)return -1;
    	pFrame = avcodec_alloc_frame();
    	if(pFrame == NULL)return -1;
    	// Make a screen to put our video
    #ifndef __DARWIN__
    	screen = SDL_SetVideoMode(pCodecCtx->width, pCodecCtx->height, 0, 0);
    #else
    	screen = SDL_SetVideoMode(pCodecCtx->width, pCodecCtx->height, 24, 0);
    #endif
    	if(!screen) {
    		fprintf(stderr, "SDL: could not set video mode - exiting
    ");
    		exit(1);
    	}
    	// Allocate a place to put our YUV image on that screen
    	bmp = SDL_CreateYUVOverlay(pCodecCtx->width,
    			pCodecCtx->height,
    			SDL_YV12_OVERLAY,
    			screen);
     	img_convert_ctx = sws_getContext(pCodecCtx->width,  
                              pCodecCtx->height, pCodecCtx->pix_fmt,  
                              pCodecCtx->width, pCodecCtx->height,  
                              PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);  
    
    	// Read frames and save first five frames to disk
    	i=0;
    	while(av_read_frame(pFormatCtx, &packet)>=0) {
    		// Is this a packet from the video stream?
    		if(packet.stream_index==videoStream) {
    			avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
    			// Did we get a video frame?
    			if(frameFinished) {
    				SDL_LockYUVOverlay(bmp);
    				
    				AVPicture *pict;
    				pict->data[0] = bmp->pixels[0];
    				pict->data[1] = bmp->pixels[2];
    				pict->data[2] = bmp->pixels[1];
    
    				pict->linesize[0] = bmp->pitches[0];
    				pict->linesize[1] = bmp->pitches[2];
    				pict->linesize[2] = bmp->pitches[1];
    				
    sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pict->data, pict->linesize);
    				SDL_UnlockYUVOverlay(bmp);
    
    				rect.x = 0;
    				rect.y = 0;
    				rect.w = pCodecCtx->width;
    				rect.h = pCodecCtx->height;
    				SDL_DisplayYUVOverlay(bmp, &rect);
    
    			}
    		}
    		// Free the packet that was allocated by av_read_frame
    		av_free_packet(&packet);
    		SDL_PollEvent(&event);
    		switch(event.type) {
    			case SDL_QUIT:
    				SDL_Quit();
    				exit(0);
    				break;
    			default:
    				break;
    		}
    
    	}
    	// Free the YUV frame
    	av_free(pFrame);
    
    	// Close the codec
    	avcodec_close(pCodecCtx);
    
    	// Close the video file
    	av_close_input_file(pFormatCtx);
    }


    2、编译结果如下:

    root@zhangjie:/Graduation/jni# ndk-build
    Install        : libSDL.so => libs/armeabi/libSDL.so
    Install        : libffmpeg-neon.so => libs/armeabi/libffmpeg-neon.so
    Compile arm    : ffmpeg-test-neon <= Decodec_Video.c
    /Graduation/jni/jniffmpeg/Decodec_Video.c: In function 'Java_com_zhangjie_graduation_videopalyer_jni_VideoPlayerDecode_VideoPlayer':
    /Graduation/jni/jniffmpeg/Decodec_Video.c:106:1: warning: passing argument 2 of 'sws_scale' from incompatible pointer type [enabled by default]
    /Graduation/jni/jniffmpeg/../ffmpeg/libswscale/swscale.h:237:5: note: expected 'uint8_t const * const*' but argument is of type 'uint8_t **'
    /Graduation/jni/jniffmpeg/Decodec_Video.c:137:2: warning: 'av_close_input_file' is deprecated (declared at /Graduation/jni/jniffmpeg/../ffmpeg/libavformat/avformat.h:1533) [-Wdeprecated-declarations]
    SharedLibrary  : libffmpeg-test-neon.so
    Install        : libffmpeg-test-neon.so => libs/armeabi/libffmpeg-test-neon.so

    3、SDL1.3源码

    http://download.csdn.net/detail/jwzhangjie/5596453

    4、之前在Android本地视频播放器开发--NDK编译FFmpeg中没有添加swscale功能,所以需要重新编译ffmpeg,其脚本如下:

    NDK=/opt/android-ndk-r8d
    PLATFORM=$NDK/platforms/android-8/arch-arm/
    PREBUILT=$NDK/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86
    LOCAL_ARM_NEON=true
    CPU=armv7-a
    OPTIMIZE_CFLAGS="-mfloat-abi=softfp -mfpu=neon -marm -mcpu=cortex-a8"
    PREFIX=./android/$CPU
    ./configure --target-os=linux 
        --prefix=$PREFIX 
        --enable-cross-compile 
        --arch=arm 
        --enable-nonfree 
        --enable-asm 
        --cpu=cortex-a8 
        --enable-neon 
        --cc=$PREBUILT/bin/arm-linux-androideabi-gcc 
        --cross-prefix=$PREBUILT/bin/arm-linux-androideabi- 
        --nm=$PREBUILT/bin/arm-linux-androideabi-nm 
        --sysroot=$PLATFORM 
        --extra-cflags=" -O3 -fpic -DANDROID -DHAVE_SYS_UIO_H=1 $OPTIMIZE_CFLAGS " 
        --disable-shared 
        --enable-static 
        --extra-ldflags="-Wl,-rpath-link=$PLATFORM/usr/lib -L$PLATFORM/usr/lib  -nostdlib -lc -lm -ldl -llog" 
        --disable-ffmpeg 
        --disable-ffplay 
        --disable-ffprobe 
        --disable-ffserver 
        --disable-encoders 
        --enable-avformat 
        --disable-optimizations 
        --disable-doc 
        --enable-pthreads 
        --disable-yasm 
        --enable-zlib 
        --enable-pic 
        --enable-small
    
    #make clean
    make  -j4 install
    
    $PREBUILT/bin/arm-linux-androideabi-ar d libavcodec/libavcodec.a inverse.o
    
    $PREBUILT/bin/arm-linux-androideabi-ld -rpath-link=$PLATFORM/usr/lib -L$PLATFORM/usr/lib  -soname libffmpeg-neon.so -shared -nostdlib  -z noexecstack -Bsymbolic --whole-archive --no-undefined -o $PREFIX/libffmpeg-neon.so libavcodec/libavcodec.a libavformat/libavformat.a libavutil/libavutil.a  libavfilter/libavfilter.a libswresample/libswresample.a libswscale/libswscale.a libavdevice/libavdevice.a -lc -lm -lz -ldl -llog  --warn-once  --dynamic-linker=/system/bin/linker $PREBUILT/lib/gcc/arm-linux-androideabi/4.4.3/libgcc.a
  • 相关阅读:
    《linux内核设计与实现》读书笔记第十八章
    20135337朱荟潼 Linux第八周学习总结——进程的切换和系统的一般执行过程
    2013337朱荟潼 Linux第四章读书笔记——进程调度
    2013337朱荟潼 Linux&深入理解计算机系统第七章读书笔记——链接
    20135337朱荟潼 Linux第七周学习总结——可执行程序的装载
    2013337朱荟潼 Linux第三章读书笔记——进程管理
    20135337朱荟潼 Linux第六周学习总结——进程的描述和进程的创建
    2013337朱荟潼 Linux第十八章读书笔记——调试
    20135337朱荟潼 Linux第五周学习总结——扒开系统调用的三层皮(下)
    2013337朱荟潼 Linux第五章读书笔记——系统调用
  • 原文地址:https://www.cnblogs.com/snake-hand/p/3141144.html
Copyright © 2011-2022 走看看