热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

android平台下基于ffmpeg和ANativeWindow实现简单的视频播放器

音视频实践学习android全平台编译ffmpeg以及x264与fdk-aac实践ubuntu下使用nginx和nginx-rtmp-module配置直播推流服务器android

音视频实践学习


  • 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) {//1.初始化所有组件av_register_all();//分配一个AVFormatContext结构pFormatCtx &#61; avformat_alloc_context();//2.打开输入文件if (avformat_open_input(&pFormatCtx, input_str, NULL, NULL) !&#61; 0) {LOGE("Could not open input stream");goto end_line;}//3.查找文件的流信息if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {LOGE("Could not find stream information");goto end_line;}//4.查找视频轨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;}//5.查找解码器vCodec &#61; avcodec_find_decoder(pFormatCtx->streams[videoIndex]->codecpar->codec_id);if (vCodec &#61;&#61; NULL) {LOGE("could not find codec");goto end_line;}//6.配置解码器vCodecCtx &#61; avcodec_alloc_context3(vCodec);avcodec_parameters_to_context(vCodecCtx, pFormatCtx->streams[videoIndex]->codecpar);//7.打开解码器if (avcodec_open2(vCodecCtx, vCodec, NULL) < 0) {LOGE("Could not open codec");goto end_line;}width &#61; vCodecCtx->width;height &#61; vCodecCtx->height;//分配一个帧指针&#xff0c;指向解码后的原始帧vFrame &#61; av_frame_alloc();vPacket &#61; (AVPacket *) av_malloc(sizeof(AVPacket));pFrameRGBA &#61; av_frame_alloc();//绑定输出bufferbufferSize &#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);//默认为RGB565if (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


推荐阅读
  • Scala 实现 UTF-8 编码属性文件读取与克隆
    本文介绍如何使用 Scala 以 UTF-8 编码方式读取属性文件,并实现属性文件的克隆功能。通过这种方式,可以确保配置文件在多线程环境下的一致性和高效性。 ... [详细]
  • 深入理解Java泛型:JDK 5的新特性
    本文详细介绍了Java泛型的概念及其在JDK 5中的应用,通过具体代码示例解释了泛型的引入、作用和优势。同时,探讨了泛型类、泛型方法和泛型接口的实现,并深入讲解了通配符的使用。 ... [详细]
  • 本文详细探讨了JDBC(Java数据库连接)的内部机制,重点分析其作为服务提供者接口(SPI)框架的应用。通过类图和代码示例,展示了JDBC如何注册驱动程序、建立数据库连接以及执行SQL查询的过程。 ... [详细]
  • Explore a common issue encountered when implementing an OAuth 1.0a API, specifically the inability to encode null objects and how to resolve it. ... [详细]
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • 本文详细介绍了Java中org.eclipse.ui.forms.widgets.ExpandableComposite类的addExpansionListener()方法,并提供了多个实际代码示例,帮助开发者更好地理解和使用该方法。这些示例来源于多个知名开源项目,具有很高的参考价值。 ... [详细]
  • 深入解析Spring Cloud Ribbon负载均衡机制
    本文详细介绍了Spring Cloud中的Ribbon组件如何实现服务调用的负载均衡。通过分析其工作原理、源码结构及配置方式,帮助读者理解Ribbon在分布式系统中的重要作用。 ... [详细]
  • 本文深入探讨了 Java 中的 Serializable 接口,解释了其实现机制、用途及注意事项,帮助开发者更好地理解和使用序列化功能。 ... [详细]
  • 本文详细介绍了Akka中的BackoffSupervisor机制,探讨其在处理持久化失败和Actor重启时的应用。通过具体示例,展示了如何配置和使用BackoffSupervisor以实现更细粒度的异常处理。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • XNA 3.0 游戏编程:从 XML 文件加载数据
    本文介绍如何在 XNA 3.0 游戏项目中从 XML 文件加载数据。我们将探讨如何将 XML 数据序列化为二进制文件,并通过内容管道加载到游戏中。此外,还会涉及自定义类型读取器和写入器的实现。 ... [详细]
  • 从 .NET 转 Java 的自学之路:IO 流基础篇
    本文详细介绍了 Java 中的 IO 流,包括字节流和字符流的基本概念及其操作方式。探讨了如何处理不同类型的文件数据,并结合编码机制确保字符数据的正确读写。同时,文中还涵盖了装饰设计模式的应用,以及多种常见的 IO 操作实例。 ... [详细]
  • 本文介绍如何使用阿里云的fastjson库解析包含时间戳、IP地址和参数等信息的JSON格式文本,并进行数据处理和保存。 ... [详细]
  • andr ... [详细]
  • 解决JAX-WS动态客户端工厂弃用问题并迁移到XFire
    在处理Java项目中的JAR包冲突时,我们遇到了JaxWsDynamicClientFactory被弃用的问题,并成功将其迁移到org.codehaus.xfire.client。本文详细介绍了这一过程及解决方案。 ... [详细]
author-avatar
阿宝宝86
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有