音视频实践学习
- android全平台编译ffmpeg以及x264与fdk-aac实践
- ubuntu下使用nginx和nginx-rtmp-module配置直播推流服务器
- android全平台编译ffmpeg合并为单个库实践
- android-studio使用cmake编译ffmpeg实践
- android全平台下基于ffmpeg解码MP4视频文件为YUV文件
- android全平台编译ffmpeg支持命令行实践
- android全平台基于ffmpeg解码本地MP4视频推流到RTMP服务器
- android平台下音频编码之编译LAME库转码PCM为MP3
- ubuntu平台下编译vlc-android视频播放器实践
- 图解YU12、I420、YV12、NV12、NV21、YUV420P、YUV420SP、YUV422P、YUV444P的区别
- 图解RGB565、RGB555、RGB16、RGB24、RGB32、ARGB32等格式的区别
- YUV420P、YUV420SP、NV12、NV21和RGB互相转换并存储为JPEG以及PNG图片
- android全平台编译libyuv库实现YUV和RGB的转换
- android平台下基于ffmpeg对相机采集的NV21数据编码为MP4视频文件
- android平台下基于ffmpeg采集Camera数据编码成H.264推流到RTMP服务器
- android平台下基于ffmpeg和ANativeWindow实现简单的视频播放器
概述
本节内容旨在了解本地视频的解码播放过程
,暂时不设计音频的解码同步播放
操作。
流程分析

工程实践
新建工程ffmpeg-single-play

定义java层的播放类:
package com.onzhou.ffmpeg.player;public class NativePlayer {static {System.loadLibrary("native-player");}public native int playVideo(String videoPath, Object surface);}
定义好本地的播放器头文件:native_play.h
class NativePlayer {private:int width = 0;int height = 0;int bufferSize = 0;int videoIndex = -1;AVPacket *vPacket = NULL;AVFrame *vFrame = NULL, *pFrameRGBA = NULL;AVCodecContext *vCodecCtx = NULL;SwsContext *sws_ctx = NULL;AVFormatContext *pFormatCtx = NULL;uint8_t *out_buffer = NULL;ANativeWindow_Buffer windowBuffer;AVCodec *vCodec = NULL;public:int PlayVideo(const char *input_str, ANativeWindow *nativeWindow);};
定义相关的实现类文件:native_play.cpp
int NativePlayer::PlayVideo(const char *input_str, ANativeWindow *nativeWindow) {av_register_all();pFormatCtx &#61; avformat_alloc_context();if (avformat_open_input(&pFormatCtx, input_str, NULL, NULL) !&#61; 0) {LOGE("Could not open input stream");goto end_line;}if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {LOGE("Could not find stream information");goto end_line;}for (int index &#61; 0; index < pFormatCtx->nb_streams; index&#43;&#43;) {if (pFormatCtx->streams[index]->codecpar->codec_type &#61;&#61; AVMEDIA_TYPE_VIDEO) {videoIndex &#61; index;break;}}if (videoIndex &#61;&#61; -1) {LOGE("Could not find a video stream");goto end_line;}vCodec &#61; avcodec_find_decoder(pFormatCtx->streams[videoIndex]->codecpar->codec_id);if (vCodec &#61;&#61; NULL) {LOGE("could not find codec");goto end_line;}vCodecCtx &#61; avcodec_alloc_context3(vCodec);avcodec_parameters_to_context(vCodecCtx, pFormatCtx->streams[videoIndex]->codecpar);if (avcodec_open2(vCodecCtx, vCodec, NULL) < 0) {LOGE("Could not open codec");goto end_line;}width &#61; vCodecCtx->width;height &#61; vCodecCtx->height;vFrame &#61; av_frame_alloc();vPacket &#61; (AVPacket *) av_malloc(sizeof(AVPacket));pFrameRGBA &#61; av_frame_alloc();bufferSize &#61; av_image_get_buffer_size(AV_PIX_FMT_RGBA, width, height, 1);out_buffer &#61; (uint8_t *) av_malloc(bufferSize * sizeof(uint8_t));av_image_fill_arrays(pFrameRGBA->data, pFrameRGBA->linesize, out_buffer, AV_PIX_FMT_RGBA,width, height, 1);sws_ctx &#61; sws_getContext(width, height, vCodecCtx->pix_fmt,width, height, AV_PIX_FMT_RGBA, SWS_BICUBIC, NULL, NULL, NULL);if (ANativeWindow_setBuffersGeometry(nativeWindow, width, height, WINDOW_FORMAT_RGBA_8888) <0) {LOGE("Could not set buffers geometry");ANativeWindow_release(nativeWindow);goto end_line;}while (av_read_frame(pFormatCtx, vPacket) >&#61; 0) {if (vPacket->stream_index &#61;&#61; videoIndex) {if (avcodec_send_packet(vCodecCtx, vPacket) !&#61; 0) {return -1;}while (avcodec_receive_frame(vCodecCtx, vFrame) &#61;&#61; 0) {sws_scale(sws_ctx, (const uint8_t *const *) vFrame->data, vFrame->linesize,0,vCodecCtx->height,pFrameRGBA->data, pFrameRGBA->linesize);if (ANativeWindow_lock(nativeWindow, &windowBuffer, NULL) < 0) {LOGE("cannot lock window");} else {uint8_t *bufferBits &#61; (uint8_t *) windowBuffer.bits;for (int h &#61; 0; h < height; h&#43;&#43;) {memcpy(bufferBits &#43; h * windowBuffer.stride * 4,out_buffer &#43; h * pFrameRGBA->linesize[0],pFrameRGBA->linesize[0]);}ANativeWindow_unlockAndPost(nativeWindow);}}}av_packet_unref(vPacket);}sws_freeContext(sws_ctx);end_line:av_free(vPacket);av_free(pFrameRGBA);avcodec_close(vCodecCtx);avformat_close_input(&pFormatCtx);return 0;
}
最终播放效果如下&#xff1a;

项目地址&#xff1a;ffmpeg-single-play
https://github.com/byhook/ffmpeg4android