android使用ffmpeg

来源:互联网 发布:activity之间传递数据 编辑:程序博客网 时间:2024/06/05 14:15

cygwin编译见上一篇文章.


在ffmpeg/arm目录中添加Android.mk 主要目的就是将动态库给发布到libs下

LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS)LOCAL_MODULE:= libavcodecLOCAL_SRC_FILES:= lib/libavcodec-55.soLOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/includeinclude $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS)LOCAL_MODULE:= libavformatLOCAL_SRC_FILES:= lib/libavformat-55.soLOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/includeinclude $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS)LOCAL_MODULE:= libswscaleLOCAL_SRC_FILES:= lib/libswscale-2.soLOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/includeinclude $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS)LOCAL_MODULE:= libavutilLOCAL_SRC_FILES:= lib/libavutil-52.soLOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/includeinclude $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS)LOCAL_MODULE:= libavfilterLOCAL_SRC_FILES:= lib/libavfilter-4.soLOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/includeinclude $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS)LOCAL_MODULE:= libwsresampleLOCAL_SRC_FILES:= lib/libswresample-0.soLOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/includeinclude $(PREBUILT_SHARED_LIBRARY)


增加Media.h

#pragma once#include <jni.h>#include <android/native_window_jni.h>#include "utils/Lock.h"#include <pthread.h>//ffmpeg 需要先定义 __STDC_CONSTANT_MACROS 才能通过 c++ 编译#define __STDC_CONSTANT_MACROS#ifndef INT64_C#define INT64_C(c) (c ## LL)#define UINT64_C(c) (c ## ULL)#endifextern "C" {#include <libavcodec/avcodec.h>#include <libavformat/avformat.h>#include <libavutil/avutil.h>#include <libavutil/dict.h>#include <libavutil/frame.h>#include <libavutil/mem.h>#include <libavutil/pixfmt.h>#include <libswscale/swscale.h>#include <libavutil/time.h>#include <libavutil/opt.h>#include <libswresample/swresample.h>}class Media{public:Media();~Media();void setSurface(JNIEnv *pEnv, jobject pSurface,int pWidth,int pHeight);bool initPath(const char * path);bool initCodec(int width,int height);int getResWidth();int getResHeight();void play();void pause();void stop();bool isPlaying();void decodeAndRenderPic(void *pBuffer,int dwBufsize);void decodeAudioAndPlay(void *pBuffer,int dwBufsize);private:static void* decodeAndRenderAdpt(void *params);void decodeAndRender();private:bool bInit;ANativeWindow* window;char *videoFileName;AVFormatContext *formatCtx;int videoStream;int               audioStream;AVCodecContext  *codecCtx;AVCodecContext  *codecCtxAudio;AVFrame         *decodedFrame;AVFrame         *frameRGBA ;jobjectbitmap;void*buffer;struct SwsContext   *sws_ctx;struct SwrContext   *swr_ctx;int width;int height;bool               _stop;pthread_t decodeThread;Mutex mutexSurface;Mutex lockWindow;};


核心代码如下:


增加Media.cpp

#include "Media.h"#include "Audio.h"//ffmpeg 需要先定义 __STDC_CONSTANT_MACROS 才能通过 c++ 编译#define __STDC_CONSTANT_MACROS#include <android/native_window_jni.h>#include <stdint.h>#include <stdio.h>#include <string.h>#include "utils/Log.h"#include "cu.h"#include <unistd.h>#include <sys/syscall.h>#include <sys/linux-syscalls.h>#define SYS_gettid __NR_gettidextern "C" {#include <libavcodec/avcodec.h>#include <libavformat/avformat.h>#include <libavutil/avutil.h>#include <libavutil/dict.h>#include <libavutil/frame.h>#include <libavutil/mem.h>#include <libavutil/pixfmt.h>#include <libswscale/swscale.h>}#define RGB_SIZE 4//AV_PIX_FMT_RGBA,AV_PIX_FMT_RGB24#define AV_FMT AV_PIX_FMT_RGBAMedia::Media():mutexSurface(true),window(NULL),lockWindow(false),frameRGBA(NULL),decodedFrame(NULL),codecCtx(NULL),formatCtx(NULL),_stop(true)       ,buffer(NULL),height(0),width(0),videoStream(-1)   ,sws_ctx(NULL),videoFileName(NULL),audioStream(-1),codecCtxAudio(NULL),swr_ctx(NULL),decodeThread(NULL){bInit = false;}Media::~Media(){stop();if(NULL!=decodeThread){pthread_join(decodeThread, NULL);}if(NULL!=window){ANativeWindow_release(window);window=NULL;}// Free the RGB imageif(NULL!=frameRGBA){av_free(frameRGBA);frameRGBA=NULL;}// Free the YUV frameif(NULL!=decodedFrame){av_free(decodedFrame);decodedFrame=NULL;}// Close the codecif(NULL!=codecCtx){avcodec_close(codecCtx);codecCtx=NULL;}// Close the video fileif(NULL!=formatCtx){avformat_close_input(&formatCtx);formatCtx=NULL;}}void Media::setSurface(JNIEnv *pEnv, jobject pSurface,int pWidth,int pHeight){LOGD("Media::setSurface start, %d,%d,%d", (int)pSurface , pWidth, pHeight);if (0 != pSurface) {if(pWidth <=0 || pHeight<=0){LOGD("Media::setSurface width or height is zero !!! %d,%d",  pWidth, pHeight);return;}if(NULL==window){synchronized(lockWindow){// get the native window referencewindow = ANativeWindow_fromSurface(pEnv, pSurface);// set format and size of window buffer WINDOW_FORMAT_RGBA_8888ANativeWindow_setBuffersGeometry(window, 0, 0, WINDOW_FORMAT_RGBA_8888);}}} else {stop();if(NULL!=window){// release the native windowsynchronized(lockWindow){ANativeWindow_release(window);window=NULL;}}return;}//reset width and heightwidth = pWidth;height = pHeight;if(NULL != buffer){free(buffer);buffer=NULL;}buffer = malloc(pWidth * pHeight * RGB_SIZE);if(NULL == buffer){LOGE("Media::setSurface Cannot malloc buffer size : %d!", pWidth * pHeight * RGB_SIZE);return;}//get the scaling contextsws_ctx = sws_getContext (codecCtx->width,codecCtx->height,codecCtx->pix_fmt,pWidth,pHeight,AV_FMT,SWS_FAST_BILINEAR,//SWS_BILINEAR,NULL,NULL,NULL);// Assign appropriate parts of bitmap to image planes in pFrameRGBA// Note that pFrameRGBA is an AVFrame, but AVFrame is a superset// of AVPictureavpicture_fill((AVPicture *)frameRGBA, (uint8_t *)buffer, AV_FMT,pWidth, pHeight);LOGD("Media::setSurface window:%d , mutexInit.isLocked: %d !", (int)window,(int) mutexSurface.isLocked());if(NULL!=window && mutexSurface.isLocked()){LOGD("Media::setSurface unlock surface!");mutexSurface.unlock();}LOGD("Media::setSurface OK!");return;}void audio_swr_resampling_audio_init(SwrContext **swr_ctx,/*TargetAudioParams *targetAudioParams,*/AVCodecContext *codec){    if(codec->sample_fmt == AV_SAMPLE_FMT_S16 /*|| codec->sample_fmt == AV_SAMPLE_FMT_S32 */||codec->sample_fmt == AV_SAMPLE_FMT_U8){        LOGE("codec->sample_fmt:%d",codec->sample_fmt);        if(*swr_ctx){            swr_free(swr_ctx);            *swr_ctx = NULL;        }        return;    }    if(*swr_ctx){        swr_free(swr_ctx);    }    *swr_ctx = swr_alloc();    if(!*swr_ctx){        LOGE("swr_alloc failed");        return;    }    /* set options */    av_opt_set_int(*swr_ctx, "in_channel_layout",    codec->channel_layout, 0);    av_opt_set_int(*swr_ctx, "in_sample_rate",       codec->sample_rate, 0);    av_opt_set_sample_fmt(*swr_ctx, "in_sample_fmt", codec->sample_fmt, 0);    av_opt_set_int(*swr_ctx, "out_channel_layout",    codec->channel_layout/*targetAudioParams->channel_layout*/, 0);    av_opt_set_int(*swr_ctx, "out_sample_rate",       codec->sample_rate/*targetAudioParams->sample_rate*/, 0);    av_opt_set_sample_fmt(*swr_ctx, "out_sample_fmt", AV_SAMPLE_FMT_S16/*targetAudioParams->sample_fmt*/, 0);// AV_SAMPLE_FMT_S16    /* initialize the resampling context */    int ret = 0;    if ((ret = swr_init(*swr_ctx)) < 0) {        LOGE("Failed to initialize the resampling context\n");        if(*swr_ctx){            swr_free(swr_ctx);            *swr_ctx = NULL;        }        return;    }}int audio_swr_resampling_audio(struct SwrContext *swr_ctx,/*TargetAudioParams *targetAudioParams,*/AVFrame *audioFrame,uint8_t **targetData){    int len = swr_convert(swr_ctx,targetData    ,audioFrame->nb_samples    ,(const uint8_t **)audioFrame->extended_data    ,audioFrame->nb_samples);    if(len < 0){        LOGE("error swr_convert");        return -1;    }    int dst_bufsize = len * audioFrame->channels/*targetAudioParams->channels*/ * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16/*targetAudioParams->sample_fmt*/);    LOGI("dst_bufsize:%d",dst_bufsize);    return dst_bufsize;}void audio_swr_resampling_audio_destory(SwrContext **swr_ctx){    if(*swr_ctx){        swr_free(swr_ctx);        *swr_ctx = NULL;    }}bool Media::initPath(const char *path){AVCodec         *pCodec = NULL;int i;AVDictionary    *optionsDict = NULL;LOGI("video file name is %s", path);// Register all formats and codecsav_register_all();// Open video fileif(avformat_open_input(&formatCtx, path, NULL, NULL)!=0)return false; // Couldn't open fileLOGD("Media::initPath pos 1");// Retrieve stream informationif(avformat_find_stream_info(formatCtx, NULL)<0)return false; // Couldn't find stream informationLOGD("Media::initPath pos 2");// Dump information about file onto standard errorav_dump_format(formatCtx, 0, path, 0);LOGD("Media::initPath pos 3");// Find the first video streamvideoStream=-1;audioStream=-1;for(i=0; i<formatCtx->nb_streams; i++) {if(formatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO) {LOGI("FIND VIDEO CODEC ID : %d" , i);videoStream=i;if(audioStream!=-1 )break;}else if(formatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO) {LOGI("FIND AUDIO CODEC ID: %d" , i);audioStream=i;if(videoStream!=-1 )break;}}LOGD("Media::initPath pos 5");if(videoStream==-1)return false; // Didn't find a video stream// Get a pointer to the codec context for the video streamcodecCtx=formatCtx->streams[videoStream]->codec;// Find the decoder for the video streampCodec=avcodec_find_decoder(codecCtx->codec_id);LOGD("Media::initPath pos 6");if(pCodec==NULL) {fprintf(stderr, "Unsupported codec!\n");return false; // Codec not found}LOGD("Media::initPath pos 7");// Open codecif(avcodec_open2(codecCtx, pCodec, &optionsDict)<0)return false; // Could not open codecLOGD("Media::initPath pos 8");// Allocate video framedecodedFrame=av_frame_alloc();LOGD("Media::initPath pos 9");// Allocate an AVFrame structureframeRGBA=av_frame_alloc();if(frameRGBA==NULL)return false;bInit=true;LOGD("Media::initPath pos 10");//audio decodecif(-1!=audioStream){codecCtxAudio = formatCtx->streams[audioStream]->codec;pCodec = avcodec_find_decoder(codecCtxAudio->codec_id);if(avcodec_open2(codecCtxAudio, pCodec, &optionsDict)<0){audioStream=-1;LOGW("Error avcodec_open2 Audio Decode!");}LOGE("codecCtxAudio data: %d, %d, %d", codecCtxAudio->bit_rate, codecCtxAudio->sample_rate, codecCtxAudio->channels);}return true;}bool Media::initCodec(int width, int height){AVCodec         *pCodec = NULL;int i;//avcodec_init();// Register all formats and codecsav_register_all();/* find the video encoder */pCodec = avcodec_find_decoder(CODEC_ID_H264);if (!pCodec){LOGE("codec not found!");return false;}codecCtx = avcodec_alloc_context3(pCodec);//初始化参数,下面的参数应该由具体的业务决定codecCtx->time_base.num = 1;codecCtx->frame_number = 1; //每包一个视频帧codecCtx->codec_type = AVMEDIA_TYPE_VIDEO;codecCtx->bit_rate = 0;codecCtx->time_base.den = 30;//帧率codecCtx->width = width;//视频宽codecCtx->height = height;//视频高codecCtx->pix_fmt = AV_PIX_FMT_YUV420P;LOGE("codecCtx init OK! %d", (int)codecCtx);// Open codecif(avcodec_open2(codecCtx, pCodec, NULL)<0)return false; // Could not open codec// Allocate video framedecodedFrame=av_frame_alloc();// Allocate an AVFrame structureframeRGBA=av_frame_alloc();if(frameRGBA==NULL)return false;//Audioint audioBitrate = 64000;int sampleRate = 44100;// 44100, 22050 and 11025.int channels=2;pCodec = avcodec_find_decoder(CODEC_ID_AAC);if (!pCodec){LOGE("codec not found!");return false;}codecCtxAudio = avcodec_alloc_context3(pCodec);codecCtxAudio->codec_type = AVMEDIA_TYPE_AUDIO;codecCtxAudio->codec_id  = AV_CODEC_ID_AAC;codecCtxAudio->sample_fmt = AV_SAMPLE_FMT_S16;codecCtxAudio->sample_rate = sampleRate;codecCtxAudio->channels = channels;/*codecCtxAudio->profile = FF_PROFILE_AAC_MAIN;codecCtxAudio->channel_layout = AV_CH_LAYOUT_STEREO;codecCtxAudio->bit_rate = audioBitrate;codecCtxAudio->time_base.num= 1;codecCtxAudio->time_base.den= sampleRate;*/codecCtxAudio->pix_fmt = PIX_FMT_NONE;if(avcodec_open2(codecCtxAudio, pCodec, NULL)<0){LOGE("codec not found!");codecCtxAudio=NULL;}bInit=true;return true;}int Media::getResWidth(){if(bInit && NULL != codecCtx)return codecCtx->width;return -1;}int Media::getResHeight(){if(bInit && NULL != codecCtx)return codecCtx->height;return -1;}void Media::play(){_stop = false;pthread_create(&decodeThread, NULL, decodeAndRenderAdpt, this);}void Media::pause(){_stop=true;}void Media::stop(){_stop=true;bInit = false;}bool Media::isPlaying(){return !_stop;}void* Media::decodeAndRenderAdpt(void *params){LOGW("create thread : %d Media::decodeAndRenderAdpt", syscall(SYS_gettid));bool bOk = AttachCurrentThread();LOGI("AttachCurrentThread Result: %d", bOk);Media *pMedia = (Media *)params;if(NULL!=pMedia->codecCtxAudio){audio_swr_resampling_audio_init(&pMedia->swr_ctx,pMedia->codecCtxAudio);initAudio(pMedia->codecCtxAudio->sample_rate,pMedia->codecCtxAudio->channels==1,pMedia->codecCtxAudio->sample_fmt != AV_SAMPLE_FMT_U8);LOGI("initAudio %d,%d,%d",pMedia->codecCtxAudio->sample_rate,pMedia->codecCtxAudio->channels,pMedia->codecCtxAudio->sample_fmt);}try{pMedia->decodeAndRender();}catch (...) {LOGE("unkown Exception in Thread: Media::decodeAndRender");}if(bOk)DetachCurrentThread();if(NULL!=pMedia->codecCtxAudio){releaseAudio();audio_swr_resampling_audio_destory(&pMedia->swr_ctx);}pMedia->decodeThread=NULL;return NULL;}void Media::decodeAndRender(){LOGD("Media::decodeAndRender check mutexInit.isLocked: %d !",(int)mutexSurface.isLocked());if(mutexSurface.isLocked()){LOGD("Media::decodeAndRender wait unlock surface!");mutexSurface.lock();mutexSurface.unlock();LOGD("Media::decodeAndRender wait unlock surface finished ok!");}ANativeWindow_Buffer windowBuffer;AVPacket        packet;int i=0;int            frameFinished;int lineCnt;longpts;long baseTime=0;longwaitTime = 0;ANativeWindow * pWin;pWin=window;uint8_t **dst_data = NULL;/* FILE *stream; stream = fopen("/sdcard/1.pcm", "wb");*/while(av_read_frame(formatCtx, &packet)>=0 && !_stop && NULL!=window && bInit) {// Is this a packet from the video stream?if(packet.stream_index==videoStream) {// Decode video frameavcodec_decode_video2(codecCtx, decodedFrame, &frameFinished,   &packet);// Did we get a video frame?if(frameFinished) {// Convert the image from its native format to RGBAsws_scale(sws_ctx,(uint8_t const * const *)decodedFrame->data,decodedFrame->linesize,0,codecCtx->height,frameRGBA->data,frameRGBA->linesize);if(packet.dts == AV_NOPTS_VALUE && decodedFrame->opaque && *(uint64_t*)decodedFrame->opaque != AV_NOPTS_VALUE){pts = *(uint64_t *)decodedFrame->opaque;LOGD("pst1: %d",pts);}else if(packet.dts != AV_NOPTS_VALUE) {  pts = packet.dts;  LOGD("pst2: %d",pts);} else {  pts = 0;  LOGD("pst3: %d",pts);}//pts = av_q2d(codecCtx->time_base) * 1000000.0 * i * 2;pts *= 1000;//LOGD("debug %d,%d,%f",pts, (long)(av_q2d(codecCtx->time_base) * 1000000.0 * i * 2), av_q2d(codecCtx->time_base));if(0 == pts || 0 == baseTime){baseTime = av_gettime() - pts;LOGD("BASETIME: %d",baseTime);}else{waitTime = (baseTime + pts) - av_gettime();LOGD("WAITTIME: %d, %d",waitTime,pts);}//waitTime = (av_q2d(codecCtx->time_base) * 1000.0 - 0.0) * 1000;if(waitTime>0)usleep(waitTime);if(!_stop){synchronized(lockWindow){if(!_stop && NULL!=window){// lock the window bufferif (ANativeWindow_lock(pWin, &windowBuffer, NULL) < 0) {LOGE("cannot lock window");} else {// draw the frame on buffer//LOGD("copy buffer %d:%d:%d", width, height, width*height*RGB_SIZE);//LOGD("window buffer: %d:%d:%d", windowBuffer.width, windowBuffer.height, windowBuffer.stride);//memcpy(windowBuffer.bits, buffer,  width * height * RGB_SIZE);if(windowBuffer.width >= windowBuffer.stride){//LOGE("1=========windowBuffer: %d,%d,%d,%d", windowBuffer.format,windowBuffer.stride,windowBuffer.width,windowBuffer.height);memcpy(windowBuffer.bits, buffer,  width * height * RGB_SIZE);}else{//LOGE("2=========windowBuffer: %d,%d,%d,%d", windowBuffer.format,windowBuffer.stride,windowBuffer.width,windowBuffer.height);//skip stride-width 跳过padding部分内存for(int i=0;i<height;++i)memcpy(windowBuffer.bits +  windowBuffer.stride * i * RGB_SIZE, buffer + width * i * RGB_SIZE, width * RGB_SIZE);}// unlock the window buffer and post it to displayANativeWindow_unlockAndPost(pWin);// count number of frames++i;}}}}}}else if(packet.stream_index==audioStream) {int ret = avcodec_decode_audio4(codecCtxAudio,decodedFrame, &frameFinished,   &packet);// LOGD("avcodec_decode_audio4, %d , ret %d" , frameFinished, ret);if(frameFinished){// LOGD("read audio play");            size_t unpadded_linesize = decodedFrame->nb_samples * av_get_bytes_per_sample((AVSampleFormat)decodedFrame->format);            /* Write the raw audio data samples of the first plane. This works             * fine for packed formats (e.g. AV_SAMPLE_FMT_S16). However,             * most audio decoders output planar audio, which uses a separate             * plane of audio samples for each channel (e.g. AV_SAMPLE_FMT_S16P).             * In other words, this code will write only the first audio channel             * in these cases.             * You should use libswresample or libavfilter to convert the frame             * to packed data. */            if(NULL!=swr_ctx)            {            int dst_linesize = 0;int dst_nb_samples =av_rescale_rnd(decodedFrame->nb_samples, decodedFrame->sample_rate, codecCtxAudio->sample_rate, AV_ROUND_UP);int dst_nb_channels = av_get_channel_layout_nb_channels(codecCtxAudio->channels ==1 ?AV_CH_LAYOUT_MONO:AV_CH_LAYOUT_STEREO);av_samples_alloc_array_and_samples(&dst_data,&dst_linesize,dst_nb_channels,dst_nb_samples,codecCtxAudio->sample_fmt == AV_SAMPLE_FMT_U8?AV_SAMPLE_FMT_U8:AV_SAMPLE_FMT_S16, 0);            int ret = audio_swr_resampling_audio(swr_ctx,decodedFrame,dst_data);            if(ret>0){            writeAudio(dst_data[0],ret);            //fwrite(dst_data[0], 1, ret, stream);            }            if (dst_data)            {            av_freep(&dst_data[0]);            }            av_freep(&dst_data);            }else{writeAudio(decodedFrame->extended_data[0], unpadded_linesize);//fwrite(decodedFrame->extended_data[0], 1, unpadded_linesize, stream);            }            //fwrite(decodedFrame->extended_data[0], 1, unpadded_linesize, audio_dst_file);            LOGD("read audio buffer: %d ,%d", unpadded_linesize, decodedFrame->linesize[0]);}else{//LOGD("===read audio buffer: %d", packet.size);//writeAudio(packet.data, packet.size);}}else{ LOGD("unkown stream index: %d", packet.stream_index);}// Free the packet that was allocated by av_read_frameav_free_packet(&packet);}//fclose(stream);LOGI("total No. of frames decoded and rendered %d", i);}void Media::decodeAndRenderPic(void *pBuffer,int dwBufsize) {ANativeWindow_Buffer windowBuffer;AVPacket        packet;int            frameFinished;int lineCnt;ANativeWindow * pWin;pWin=window;ARect rect;rect.left=0;rect.top=0;rect.right = width;rect.bottom = height;memset(&packet,0x00,sizeof(AVPacket));packet.data = (uint8_t*)pBuffer;//这里填入一个指向完整H264数据帧的指针packet.size = dwBufsize;//这个填入H264数据帧的大小// Decode video frameavcodec_decode_video2(codecCtx, decodedFrame, &frameFinished,   &packet);// Did we get a video frame?//LOGD("111111111111111111111111");if(frameFinished && NULL!=window && bInit) {// Convert the image from its native format to RGBAsws_scale(sws_ctx,(uint8_t const * const *)decodedFrame->data,decodedFrame->linesize,0,codecCtx->height,frameRGBA->data,frameRGBA->linesize);//LOGD("22222222222222222222222222222");synchronized(lockWindow){if(NULL!=window){// lock the window bufferif (ANativeWindow_lock(pWin, &windowBuffer, &rect) < 0) {LOGE("cannot lock window");} else {//LOGD("333333333333333333333333333");// draw the frame on bufferLOGD("copy buffer %d:%d:%d   lineSize:%d", width, height, width*height*RGB_SIZE, frameRGBA->linesize[0]);LOGD("RECT : %d,%d,%d,%d",rect.left,rect.top,rect.right,rect.bottom);//LOGD("window buffer: %d:%d:%d", windowBuffer.width,windowBuffer.height, windowBuffer.stride);if(windowBuffer.width >= windowBuffer.stride){//LOGE("1=========windowBuffer: %d,%d,%d,%d", windowBuffer.format,windowBuffer.stride,windowBuffer.width,windowBuffer.height);memcpy(windowBuffer.bits, buffer,  width * height * RGB_SIZE);}else{//LOGE("2=========windowBuffer: %d,%d,%d,%d", windowBuffer.format,windowBuffer.stride,windowBuffer.width,windowBuffer.height);//skip stride-width 跳过padding部分内存for(int i=0;i<height;++i)memcpy(windowBuffer.bits +  windowBuffer.stride * i * RGB_SIZE, buffer + width * i * RGB_SIZE, width * RGB_SIZE);}//LOGD("666666666666666666666666666");// unlock the window buffer and post it to displayANativeWindow_unlockAndPost(pWin);// count number of frames//SaveFrame(pEnv, bitmap, codecCtx->width, codecCtx->height, i);//stop = 1;}}}}//LOGD("44444444444444444444444");// Free the packet that was allocated by av_read_frameav_free_packet(&packet);//LOGD("5555555555555555555555555");}void Media::decodeAudioAndPlay(void *pBuffer,int dwBufsize) {AVPacket        packet;int            frameFinished;LOGD("decodeAudioAndPlay start");if(NULL == codecCtxAudio){LOGD("codecCtxAudio not init!");return;}memset(&packet,0x00,sizeof(AVPacket));packet.data = (uint8_t*)pBuffer;//这里填入一个指向完整H264数据帧的指针packet.size = dwBufsize;//这个填入H264数据帧的大小// Decode audio frameint ret = avcodec_decode_audio4(codecCtxAudio,decodedFrame, &frameFinished,   &packet);LOGD("avcodec_decode_audio4, %d , ret %d" , frameFinished, ret);// Did we get a audio frame?if(frameFinished && bInit) {size_t unpadded_linesize = decodedFrame->nb_samples * av_get_bytes_per_sample((AVSampleFormat)decodedFrame->format);writeAudio(decodedFrame->extended_data[0], unpadded_linesize);LOGD("writeAudio");}else{LOGD("writeAudio fail!");}// Free the packet that was allocated by av_read_frameav_free_packet(&packet);LOGD("decodeAudioAndPlay end");}



Audio.h 音频做成了单例模式... 没有怎么封装, 使用java的AudioTrack,使用native的话不同版本Android的so文件不一样所以不考虑了.

#pragma oncevoid initAudio(int mhz=44100,bool bMono=false,bool b16Bit=true);void writeAudio(void * buffer,int size);void releaseAudio();

Audio.cpp

#include "media/Audio.h"#include <jni.h>#include "cu.h"#include "utils/Log.h"#include "utils/sharedptr.h"#include "utils/Lock.h"#include <vector>#include <pthread.h>#include <sys/syscall.h>#include <sys/linux-syscalls.h>#define SYS_gettid __NR_gettid#define BUFFER_SIZE 1024*20static bool init = false;static jbyteArray buffer;static jobject audio_track;static jint buffer_size;static jmethodID method_write;using std::vector;struct ElementBuf{sharedptr<jbyte> buf;int size; };typedef sharedptr<ElementBuf>  SE;static vector<SE> _vector;static Mutex mutex(true);static  Mutex mutexVistor;static bool _stop = true;void* audioThread(void *params);SE pop(){mutex.lock();synchronized (mutexVistor){if(!_vector.empty()){vector<SE>::iterator iter =_vector.begin();SE e=*iter;_vector.erase(iter);return e;}}return pop();}void push(SE e){synchronized (mutexVistor){_vector.push_back(e);}mutex.unlock();}void releaseAudioRes(){LOGD("releaseAudioRes start");JNIEnv * pEnv = getEnv();jclass audio_track_cls = pEnv->FindClass("android/media/AudioTrack");// audio.stop();    //audio.release();jmethodID method_stop =pEnv->GetMethodID(audio_track_cls, "stop","()V");jmethodID method_release =pEnv->GetMethodID(audio_track_cls, "release","()V");pEnv->CallVoidMethod(audio_track, method_stop);pEnv->CallVoidMethod(audio_track, method_release);pEnv->DeleteGlobalRef(audio_track);audio_track=NULL;LOGD("releaseAudioRes end");}int g_oldMhz = 0;int g_oldbMono = false;int g_oldb16Bit = true;void initAudio(int mhz,bool bMono,bool b16Bit){    LOGD("initAudio, %d ,%d, %d",mhz,bMono,b16Bit);     _stop=false;if(init){if(g_oldMhz!=mhz||g_oldbMono!=bMono||g_oldb16Bit!=b16Bit){releaseAudioRes();}else{return;}}g_oldMhz=mhz;g_oldbMono=bMono;g_oldb16Bit=b16Bit;JNIEnv * pEnv = getEnv();jclass audio_track_cls = pEnv->FindClass("android/media/AudioTrack");jmethodID min_buff_size_id = pEnv->GetStaticMethodID(audio_track_cls,"getMinBufferSize", "(III)I");buffer_size =pEnv->CallStaticIntMethod(audio_track_cls,min_buff_size_id,mhz, //44100, 22050 and 11025.bMono?2:0x4|0x8, //0x4|0x8,//2,          /*CHANNEL_CONFIGURATION_MONO*/2);         /*ENCODING_PCM_16BIT*/LOGI("buffer_size=%i",buffer_size);buffer =pEnv->NewByteArray(BUFFER_SIZE);//buffer_size/4buffer = (jbyteArray)pEnv->NewGlobalRef(buffer);jmethodID constructor_id =pEnv->GetMethodID(audio_track_cls, "<init>","(IIIIII)V");audio_track =pEnv->NewObject(audio_track_cls,constructor_id,3,            /*AudioManager.STREAM_MUSIC*/mhz, //11025,        /*sampleRateInHz*/ 44100, 22050 and 11025.bMono?2:0x4|0x8,//0x4|0x8,//2,            /*CHANNEL_CONFIGURATION_MONO*/b16Bit?2:3,            /*ENCODING_PCM_16BIT*/buffer_size,  /*bufferSizeInBytes*/1             /*AudioTrack.MODE_STREAM*/);audio_track = (jobject)pEnv->NewGlobalRef(audio_track);//setvolumeLOGD("setStereoVolume 1");jmethodID setStereoVolume =pEnv->GetMethodID(audio_track_cls,"setStereoVolume","(FF)I");   pEnv->CallIntMethod(audio_track,setStereoVolume,1.0,1.0);LOGD("setStereoVolume 2");//playjmethodID method_play =pEnv->GetMethodID(audio_track_cls, "play","()V");   pEnv->CallVoidMethod(audio_track, method_play);//writemethod_write =pEnv->GetMethodID(audio_track_cls,"write","([BII)I");//method_write = (jmethodID)pEnv->NewGlobalRef(method_write);LOGI("initAudio OK, BufferSize/4:%d",buffer_size/4 );static pthread_t thread=NULL;if(NULL==thread)pthread_create(&thread, NULL, audioThread, NULL);init = true;}void* audioThread(void *params){LOGW("create thread : %d Audio.cpp audioThread", syscall(SYS_gettid));AttachCurrentThread();JNIEnv * env = getEnv();while(true){ SE e = pop(); if(_stop) continue; int size = e->size; int wirteSize = 0; jbyte * buf= e->buf.get(); while(size > BUFFER_SIZE) { // LOGD("writeAudio , BufferSize/4:%d",BUFFER_SIZE ); env->SetByteArrayRegion(buffer, 0,BUFFER_SIZE, buf + wirteSize); //LOGD("writeAudio , ==========" ); env->CallVoidMethod(audio_track,method_write,buffer,0,BUFFER_SIZE); wirteSize += BUFFER_SIZE; size -= BUFFER_SIZE; } if(size>0) { //LOGD("writeAudio , size:%d",size ); env->SetByteArrayRegion(buffer, 0,size, buf + wirteSize); env->CallVoidMethod(audio_track,method_write,buffer,0,size); } //LOGD("writeAudio , OK! size:%d",e->size );}DetachCurrentThread();return NULL;}void writeAudio(void * buf,int size){sharedptr<jbyte> b(new jbyte[size]);    memcpy(b.get(),buf,size);    ElementBuf *eb =new ElementBuf();    eb->buf = b;    eb->size = size;SE e(eb);push(e);}void releaseAudio(){_stop = true;}


其它相关代码:

bool AttachCurrentThread(){LOGI("AttachCurrentThread ing");JNIEnv * env;int status = 0;env = getEnv();if(NULL==env){int ret = g_jvm->AttachCurrentThread(&env, NULL);LOGI("AttachCurrentThread ok");return ret>=0;}LOGW("AttachCurrentThread fail, thread is attached");return false;}void DetachCurrentThread(){LOGI("DetachCurrentThread ing");if(NULL!=getEnv())g_jvm->DetachCurrentThread();LOGI("DetachCurrentThread ok");}
JNIEnv * getEnv(){<span style="white-space:pre"></span>JNIEnv* env;<span style="white-space:pre"></span>if (g_jvm->GetEnv((void **)&env, JNI_VERSION_1_6) != JNI_OK) {<span style="white-space:pre"></span> return NULL;<span style="white-space:pre"></span>}<span style="white-space:pre"></span>return env;}


项目的Android.mk 我这里包含了我使用的libspeex库,没用到的可以不用

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE    := cu#LOCAL_SRC_FILES := cu.cppFILE_LIST := $(wildcard $(LOCAL_PATH)/*.cpp) LOCAL_SRC_FILES += $(FILE_LIST:$(LOCAL_PATH)/%=%) FILE_LIST := $(wildcard $(LOCAL_PATH)/*.c) LOCAL_SRC_FILES += $(FILE_LIST:$(LOCAL_PATH)/%=%)FILE_LIST := $(wildcard $(LOCAL_PATH)/*/*.cpp) LOCAL_SRC_FILES += $(FILE_LIST:$(LOCAL_PATH)/%=%)LOCAL_LDLIBS := -llog -ljnigraphics -lz -landroidLOCAL_SHARED_LIBRARIES := libavformat libavcodec libswscale libavutil libwsresample libspeexinclude $(BUILD_SHARED_LIBRARY)$(call import-add-path,$(LOCAL_PATH))$(call import-add-path,$(LOCAL_PATH)/ffmpeg/arm/include)$(call import-module, ffmpeg/arm)$(call import-module, speex)include $(all-subdir-makefiles)

Application.mk:

APP_ABI := armeabi#APP_ABI := armeabi-v7aAPP_PLATFORM := android-9APP_STL := stlport_staticAPP_CPPFLAGS += -fexceptionsAPP_CFLAGS += -Wno-error=format-security


暂时贴这么多代码出来啦! 

音频视频同步展示只做了最简单的根据视屏的pts做同步,我发现pts和网上说的不太一样.
音频使用的是:java 的AudioTrack




0 0