全志Tina_dolphin播放音视频裸流(h264,pcm)验证
最近在验证tina对裸流音视频的支持,主要指h264视频裸流及pcm音频裸流。
在原始sdk中有针对很多video和audio类型的parser,但就是没有找到pcm和h264的parser,所以需要自己搞个parser,同时找到audio播放的的接口写个demo来验证。
所有支持解析类型的parser方法都在目录:/Homlet-Tina-H2_H3/package/allwinner/tina_multimedia/libcedarx/libcore/parser下
aac Android.mk atrac AwSpecialStream bd dash flac hls include mkv mov ogg pmp ts
aiff ape avi awts caf dsd flv id3 m3u9 mms mp3 playlist remux wav
amr asf AwRawStream base config.mk env g729 id3v2 Makefile.am mmshttp mpg pls sstr wvm
里面有个AwRawStream文件夹,看了里面的代码是对H264以及H265裸流的解析支持,但是代码架构中对此parser的调用支持在CdxParser.c用宏屏蔽掉了,包括AwSpecialStream。
/*
* Copyright (c) 2008-2016 Allwinner Technology Co. Ltd.
* All rights reserved.
*
* File : CdxParser.c
* Description : Parser base
* History :
*
*/ #include <CdxParser.h> #include <cdx_log.h>
#include <CdxMemory.h>
#include <CdxList.h> #include <CdxStream.h>
#include <dlfcn.h> /*************** for debug start ***********************/
#define ENABLE_RAW_STREAM_PARSER 0
#define ENABLE_SPECIAL_PARSER 0
/*************** for debug end *************************/
打开ENABLE_RAW_STREAM_PARSER重新编译打包跑了一下还是不行,调用parserPrefetch的时候直接卡住了,跟了一下代码貌似调用CdxStremRead的时候被阻塞住了。果然是废物,估计全志自己人也还没完整的打通AwRawStream的功能,所以释放sdk的时候直接屏蔽不调用。
只能靠自己来实现裸流的的parser了。
首先验证PCM裸流。
pcm裸流文件没有文件头信息,所以一些参数无法从裸流文件中获取,需要人为设置,不像wav或者MP3这种经过打包的音频文件,文件头信息中已经包含了需要的信息。
要播放音频至少需要以下几个信息:
1、采样频率(Sampling Rate):单位时间内采集的样本数,即:采样周期的倒数,指两个采样之间的时间间隔。采样频率越高,声音质量越好,但同时占用的带宽越大。一般情况下,22KHz相当于普通FM的音质,44KHz相当于CD音质,目前的常用采样频率都不超过48KHz。
2、采样位数:表示一个样本的二进制位数,即:每个采样点用多少比特表示。计算机中音频的量化深度一般为4、8、16、32位(bit)等。例如:采样位数为8 bit时,每个采样点可以表示256个不同的采样值,而采样位数为16 bit时,每个采样点可以表示65536个不同的采样值。采样位数的大小影响声音的质量,采样位数越多,量化后的波形越接近原始波形,声音的质量越高,而需要的存储空间也越多;位数越少,声音的质量越低,需要的存储空间越少。一般情况下,CD音质的采样位数是16 bit,移动通信是8 bit。
3、声道数:记录声音时,如果每次生成一个声波数据,称为单声道;每次生成两个声波数据,称为双声道(立体声)。单声道的声音只能使用一个喇叭发声,双声道的PCM可以使两个喇叭同时发声(一般左右声道有分工),更能感受到空间效果。
4、时长:持续采样时间,可以设置的范围较大,可以使用20ms,也可以使用200ms,一般来说时间越短时延越小。
一帧PCM元数据的大小
Size(Byte) = 采样频率(Hz)× 采样时长(S)×(采样位数 / 8)× 声道数(单声道为1,立体声为2)
首先实现一个读取pcm文件流的parser
rawPcmParser.c主要负责一帧一阵的读取pcm文件流。
#define LOG_TAG "rawParser"
#include <rawPcmParser.h> static CdxPlaybkCfg initPlybkCfg =
{
.nRoutine = 0,
.nNeedDirect = 0,
.nChannels = 2,
.nSamplerate = 44100,
.nBitpersample = 16,
.nDataType = AUDIO_RAW_DATA_PCM,
}; /*
* user call this first
* input: file and rawPcmParserT
*
* */
int RawPcmParserInit(rawPcmParserT *p, const char *file)
{
if(NULL == p || NULL == file) {
loge("parmer wrong p:%p, file:%p", p, file);
return -1;
}
p->pcmFp = fopen(file, "rb");
if(NULL == p->pcmFp) {
loge("open %s failed %s",file, strerror(errno));
return -2;
}
p->mBuffer = malloc(MAX_BUFFER_SIZE);
if(NULL == p->mBuffer) {
return -3;
} fseek(p->pcmFp, 0, SEEK_END);
p->fileSize = ftell(p->pcmFp);
fseek(p->pcmFp, 0, SEEK_SET);
p->mSampleInterval = SAMPLE_INTERVAL; p->status = RAW_PCM_IDLE;
/*init cfg*/
p->mPlaybkcfg = initPlybkCfg;
p->mUnitSize = (p->mPlaybkcfg.nSamplerate *
(p->mPlaybkcfg.nBitpersample >> 3) *
p->mPlaybkcfg.nChannels *
p->mSampleInterval / 1000);
loge("file:%s size:%lld ch:%d rate:%d bit:%d type:%d, unitSize:%d",
file,p->fileSize, p->mPlaybkcfg.nChannels,
p->mPlaybkcfg.nSamplerate,
p->mPlaybkcfg.nBitpersample,
p->mPlaybkcfg.nDataType,
p->mUnitSize);
return 0;
} /*
* get media info
*
*
*/
int RawPcmParserGetCfg(rawPcmParserT *p, CdxPlaybkCfg *pCfg)
{
if(NULL == p || NULL == pCfg) {
loge("parmer wrong p:%p pCfg:%p", p, pCfg);
return -1;
} if(p->status == RAW_PCM_UNKNOWN) {
loge("status unknown");
return -2;
} /*set cfg*/
*pCfg = p->mPlaybkcfg;
return 0;
} /*
* prefet data
* return data len
*
*/ int RawPcmParserPrefetch(rawPcmParserT *p)
{
if(NULL == p || NULL == p->mBuffer) {
loge("parmer wrong p:%p", p);
return -1;
} if(p->status != RAW_PCM_IDLE) {
loge("status not idel");
return -2;
}
p->status = RAW_PCM_PREFETCHING;
int len = fread(p->mBuffer, 1, p->mUnitSize, p->pcmFp);
//if (len != p->mUnitSize) {
if (len <= 0) {
loge("read ret:(%d)%s",len, strerror(errno));
return -1;
}
p->status = RAW_PCM_PREFETCHED;
return len;
} /*get pcm data*/
unsigned char* RawPcmParserRead(rawPcmParserT *p)
{
if(NULL == p) {
loge("parmer wrong p:%p", p);
return NULL;
}
if(p->status != RAW_PCM_PREFETCHED) {
loge("have not prefetched");
return NULL;
}
p->status = RAW_PCM_IDLE; return p->mBuffer;
} /*
* must call this when exit
* close file fp
*
*/
int RawPcmParserDestroy(rawPcmParserT *p)
{
if( p ) {
if ( p->pcmFp) {
fclose(p->pcmFp);
}
if(p->mBuffer)
free(p->mBuffer);
p->status = RAW_PCM_UNKNOWN;
return 0;
}
return -1;
}
然后参照xplayerdemo,调用tinasoundcontrol的接口来播放,主要用到三个函数
在tinasoundcontrol.h中,
SoundCtrl* TinaSoundDeviceInit(); void TinaSoundDeviceSetFormat(SoundCtrl* s,CdxPlaybkCfg* cfg); int TinaSoundDeviceWrite(SoundCtrl* s, void* pData, int nDataSize); void TinaSoundDeviceDestroy(SoundCtrl* s);
第一步
创建一个SoundCtrl,
第二步
设置参数pcm参数
第三步
循环读取pcm并write到sound dev
第四步
销毁SoundCtrl
参照sdk中的libcedarx/libcedarx/demo/目录下的demo例程序,新建一个demoPcmPlayer目录存放自己demo代码。
还需要修改libcedarx/configure.as及demo/Makefile.am把自己的目录加入,使其自动编译。
player核心代码如下。
/*
*
* File : demoPcmPlayer.c
* Description :demoPcmPlayer
* History :
*
*/
#define LOG_TAG "demoPcmPlayer"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <pthread.h>
#include <sys/time.h>
#include "cdx_config.h"
#include <cdx_log.h>
#include <CdxParser.h> /********************/
#include <tinasoundcontrol.h>
#include <rawPcmParser.h>
/*******************/ /*pcm audio player run*/
void *audioThread(void* param)
{
PcmPlayerDemo *pPlayer = (PcmPlayerDemo *)param;
rawPcmParserT *parser = &(pPlayer->mRawPcmParser);
CdxPlaybkCfg *pCfg = &(pPlayer->mPlaybkCfg); int nRet = 0;
pPlayer->mPlayFrame=0; /*****************************************************************/
/*init parser*/
if(RawPcmParserInit(parser, (const char*)pPlayer->pInputFile) < 0) {
loge("init raw pcm parser failed");
return NULL;
}
RawPcmParserGetCfg(parser, pCfg); /*init soundCtrl*/
pPlayer->pSoundCtrl = TinaSoundDeviceInit();
if(NULL == pPlayer->pSoundCtrl) {
loge("init sound dev failed");
goto audio_exit;
} TinaSoundDeviceSetFormat(pPlayer->pSoundCtrl, pCfg);
if(TinaSoundDeviceStart(pPlayer->pSoundCtrl) < 0) {
loge("start sound dev failed");
goto audio_exit;
} /****************************************************************/
loge("start run!");
while ( (nRet = RawPcmParserPrefetch(parser)) > 0)
{
usleep(100); unsigned char *pcmData = RawPcmParserRead(parser);
if(NULL == pcmData) {
loge("read pcm data error ");
goto audio_exit;
}
/*send pcm data to sound dev*/
if(TinaSoundDeviceWrite(pPlayer->pSoundCtrl, (void*)pcmData, nRet) <= 0) {
loge("write pcm data error ");
goto audio_exit;
}
}
logw("get pcm end"); audio_exit:
/***************/
if(pPlayer->pSoundCtrl) {
loge("destroy sound dev and rawpcm parser");
TinaSoundDeviceStop(pPlayer->pSoundCtrl);
TinaSoundDeviceDestroy(pPlayer->pSoundCtrl);
}
RawPcmParserDestroy(parser);
/*************/
logw("exit..... ");
return NULL;
}
在TinaH3的板子上验证可以播放pcm文件。
完整的demo放在https://github.com/voidSem/AwTinaH3demoPcmPlayer上
全志Tina_dolphin播放音视频裸流(h264,pcm)验证的更多相关文章
- 音视频处理之H264编码标准20170906
一. H264基础概念 1.名词解释 场和帧 : 视频的一场或一帧可用来产生一个编码图像.在电视中,为减少大面积闪烁现象,把一帧分成两个隔行的场. 片: 每个图象中,若干 ...
- android 54 播放音视频
mainActivity: package com.sxt.day07_09; import java.util.ArrayList; import java.util.HashMap; import ...
- Android 多媒体 播放音视频
1.播放音频 因为涉及到读取文件,所以需要申请权限 <uses-permission android:name="android.permission.WRITE_EXTERNAL_S ...
- Qt播放音视频文件报错DirectShowPlayerService::doRender: Unresolved error code 0x80040266或DirectShowPlayerService::doSetUrlSource: Unresolved error code 0x80004005 ()
使用QMediaPlayer和QVideoWidget QHBoxLayout *m_layout=newQHBoxLayout(this); QMediaPlayer *m_player = new ...
- pjsip 播放音视频
http://blog.csdn.net/leixiaohua1020/article/details/40246783 onCallMediaState回调里,解码方向,获取ci.media[i]. ...
- 音视频】5.ffmpeg命令分类与使用
GT其实平时也有一些处理音视频的个人或者亲人需求,熟练使用ffmpeg之后也不要借助图示化软件,一个命令基本可以搞定 G: 熟练使用ffmpeg命令!T :不要死记硬背,看一遍,自己找下规律,敲一遍, ...
- android音视频点/直播模块开发
音视频 版权声明:本文为博主原创文章,未经博主允许不得转载. 前言 随着音视频领域的火热,在很多领域(教育,游戏,娱乐,体育,跑步,餐饮,音乐等)尝试做音视频直播/点播功能,那么作为开发一个小白, ...
- Android音视频点/直播模块开发实践总结-zz
随着音视频领域的火热,在很多领域(教育,游戏,娱乐,体育,跑步,餐饮,音乐等)尝试做音视频直播/点播功能.那么作为开发一个小白,如何快速学习音视频基础知识,了解音视频编解码的传输协议,编解码方式,以及 ...
- vlc源码分析(五) 流媒体的音视频同步
vlc播放流媒体时实现音视频同步,简单来说就是发送方发送的RTP包带有时间戳,接收方根据此时间戳不断校正本地时钟,播放音视频时根据本地时钟进行同步播放.首先了解两个概念:stream clock和sy ...
随机推荐
- PHP中的垃圾回收相关函数
之前我们已经学习过 PHP 中的引用计数以及垃圾回收机制的概念.这些内容非常偏理论,也是非常常见的面试内容.而今天介绍的则是具体的关于垃圾回收的一些功能函数.关于之前的两篇介绍文章,大家可以到文章底部 ...
- 关于php的ini文件相关操作函数浅析
在小公司,特别是创业型公司,整个服务器的搭建一般也是我们 PHP 开发工程师的职责之一.其中,最主要的一项就是要配置好服务器的 php.ini 文件.一些参数会对服务器的性能产生深远的影响,而且也有些 ...
- Dapr + .NET Core实战(五)Actor
什么是Actor模式 Actors 为最低级别的"计算单元" 以上解释来自官方文档,看起来"晦涩难懂".大白话就是说Actors模式是一段需要单线程执行的代码块 ...
- jmeter5.2 性能测试 资源监控 JMeterPlugins1.4 ServerAgent2.2.1
一.性能工具的安装部署 1.下载JMeterPlugins-Standard-1.4.0.zip的安装包 2.解压JMeterPlugins-Standard-1.4.0.zip,将其中\lib\ex ...
- 鸿蒙内核源码分析(字符设备篇) | 字节为单位读写的设备 | 百篇博客分析OpenHarmony源码 | v67.01
百篇博客系列篇.本篇为: v67.xx 鸿蒙内核源码分析(字符设备篇) | 字节为单位读写的设备 | 51.c.h.o 文件系统相关篇为: v62.xx 鸿蒙内核源码分析(文件概念篇) | 为什么说一 ...
- P4173-残缺的字符串【FFT】
正题 题目链接:https://www.luogu.com.cn/problem/P4173 题目大意 给出两个字符串\(S,T\),其中包含小写字母和一些\(?\),\(?\)可以匹配任何字符. 求 ...
- P7581-「RdOI R2」路径权值【长链剖分,dp】
正题 题目链接:https://www.luogu.com.cn/problem/P7581 题目大意 给出\(n\)个点的有边权有根树,\(m\)次询问一个节点\(x\)的所有\(k\)级儿子两两之 ...
- ❤️❤️新生代农民工爆肝8万字,整理Python编程从入门到实践(建议收藏)已码:8万字❤️❤️
@ 目录 开发环境搭建 安装 Python 验证是否安装成功 安装Pycharm 配置pycharm 编码规范 基本语法规则 保留字 单行注释 多行注释 行与缩进 多行语句 数据类型 空行 等待用户输 ...
- HCNP Routing&Switching之路由引入
前文我们了解了路由控制技术策略路由相关话题,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/15333139.html:今天我们来聊一聊路由引入技术相关话题: 路 ...
- LuoguP1557 Kruscal的加法 题解
题目Link 就是这道题,做了我整整一天! 看到题目,首先想到的就是:就这?就这一道大水题也能是绿?然后十分钟写完代码,提交-- 果不其然,绿题不是白绿的,看了一眼数据和讨论,又得写高精了-- 先附上 ...