全志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

原文地址:https://www.cnblogs.com/tid-think/p/10869771.html

时间: 2024-08-25 01:46:05

全志Tina_dolphin播放音视频裸流(h264,pcm)验证的相关文章

H.264/ACC音视频编码流的RTP/RTSP传输实现(1)

目标: 实现一个用于H.264/ACC音视频编码流的RTP/RTSP传输的简单服务器,主要通过此过程学习基于RTP的NAL.ADTS码流封装技术和基于RTSP的视频交互控制技术.完整系统应该包括服务器和客户端两个部分,其中服务器负责接收客户端请求.封包以及发送音视频数据,客户端负责发送请求和接收视频数据.分别在Windows平台上和Android平台上进行网络传输实体测试,通过客户端网络流抓包和播放器播放对系统进行进一步验证. 简介: 随着互联网和移动通信的飞速发展,H.264凭借其突出的编码效

视频直播技术(四):使用Ijkplayer播放音视频不同步解决方案

在开始使用过程当中对rtmp视频流进行播放,会出现严重的视频音频不同步现象,并且随着播放的时间越长,视频与音频的差距越大. 解决方案 具体原因是CPU在处理视频帧的时候处理得太慢,默认的音视频同步方案是视频同步到音频, 导致了音频播放过快,视频跟不上. framedorp 控制着允许丢帧的范围 可以通过修改 framedrop 的数值来解决不同步的问题,framedrop 是在视频帧处理不过来的时候丢弃一些帧达到同步的效果.具体设置: IJKFFOptions *options = [IJKFF

H.264/ACC音视频编码流的RTP/RTSP传输实现(4)

实时流协议RTSP RTSP[[[] Schulzrinne,H., Rao.Real time streaming protocol (RTSP) RFC 2326[J]. IETF .1998]]由RealNetworks.Netscape Communications和哥伦比亚大学共同开发而成.1998年5月,IETF作为建议标准发布.RTSP是从HTTP协议框架上继承而来,拥有着HTTP的大部分特性.RTSP(Real Time Stream Protocol,实时流协议)是应用级协议,

android 54 播放音视频

mainActivity: package com.sxt.day07_09; import java.util.ArrayList; import java.util.HashMap; import android.app.Activity; import android.content.ContentResolver; import android.content.Context; import android.database.Cursor; import android.graphics

H.264/ACC音视频编码流的RTP/RTSP传输实现(2)

H.264编码基本原理 为达到良好的编码效率及性能,H.264编码器采用的仍是变换和预测的混合编码法,[[[] 毕厚杰. 新一代视频压缩编码标准: H. 264/AVC[M]. 人民邮电出版社, 2005]]其完整的编码过程如图2-1所示. 在H.264编码标准中,输入的帧或场Fn是以宏块为单位进行处理的,采样后的视频图像都被分成16*16的宏块每个宏块包括1个亮度子块和2个8*8的色度子块.在分割宏块后,宏块按照相应次序进行编码器进行压缩编码.在H.264编码过程中,首先按照根据编码速率.编码

ubuntu下 gstreamer 的配置及播放音视频例子

官方网址:http://gstreamer.freedesktop.org Gstreamer安装: 使用sudo apt-get install 安装 sudo apt-get install libgstreamer0.10-dev gstreamer-tools gstreamer0.10-tools gstreamer0.10-doc sudo apt-get install gstreamer0.10-plugins-base gstreamer0.10-plugins-good gs

android音视频点/直播模块开发

前言 随着音视频领域的火热,在很多领域(教育,游戏,娱乐,体育,跑步,餐饮,音乐等)尝试做音视频直播/点播功能,那么作为开发一个小白,如何快速学习音视频基础知识,了解音视频编解码的传输协议,编解码方式,以及如何技术选型,如何解决遇到的坑,本文抛砖引玉,欢迎大咖交流. 一. 音视频的基础知识 1.1 基本概念 视频是什么 静止的画面叫图像(picture).连续的图像变化每秒超过24帧(frame)画面以上时,根椐视觉暂留原理, 人眼无法辨别每付单独的静态画面,看上去是平滑连续的视觉效果.这样的连

vlc源码分析(五) 流媒体的音视频同步

http://www.cnblogs.com/jiayayao/p/6890882.html vlc播放流媒体时实现音视频同步,简单来说就是发送方发送的RTP包带有时间戳,接收方根据此时间戳不断校正本地时钟,播放音视频时根据本地时钟进行同步播放.首先了解两个概念:stream clock和system clock.stream clock是流时钟,可以理解为RTP包中的时间戳:system clock是本地时钟,可以理解为当前系统的Tick数.第一个RTP包到来时: fSyncTimestamp

Android音视频点/直播模块开发实践总结-zz

随着音视频领域的火热,在很多领域(教育,游戏,娱乐,体育,跑步,餐饮,音乐等)尝试做音视频直播/点播功能.那么作为开发一个小白,如何快速学习音视频基础知识,了解音视频编解码的传输协议,编解码方式,以及如何技术选型,如何解决遇到的坑. 一. 音视频的基础知识 1.1 基本概念 视频是什么 静止的画面叫图像(picture).连续的图像变化每秒超过24帧(frame)画面以上时,根椐视觉暂留原理,人眼无法辨别每付单独的静态画面,看上去是平滑连续的视觉效果.这样的连续画面叫视频.当连续图像变化每秒低于