一、重采样流程

  重采样(解码音频数据之后格式不可以直接播放,需要重采样,类似图像的像素转换)
    1.分配上下文
    2.设置参数(分为(前几个是)输出格式和(后几个)输入格式,两个相对应的) 可以通过改变样本率来改变音频的播放速度,但是会失帧。
    3.初始化
    4.开始转换

二、相关函数说明

   1、 SwrContext *actx = swr_alloc(); //进行分配和初始化
   2、 actx = swr_alloc_set_opts(actx,
              av_get_default_channel_layout(2), //输出标准(左右声道)
              AV_SAMPLE_FMT_S16, //样本格式:float 、s16、s24
              ac->sample_rate,//样本率,一般使用原始的
              av_get_default_channel_layout(ac->channels),
              ac->sample_fmt,
              ac->sample_rate,
              0,0 );
   3、 re = swr_init(actx);
   4、 //将一帧一帧的音频进行重采样 (参数对应输入输出)
       int len = swr_convert(actx, //重采样上下文
              out, //输出的指针
              frame->nb_samples, //样本数量:单声道的样本数量
              (const uint8_t**)frame->data,//解码出来的data
              frame->nb_samples);//单通的样本数量

代码说明:

#include <jni.h>
#include <string>
#include <android/log.h>
#include <android/native_window.h>
#include <android/native_window_jni.h>
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,"testff",__VA_ARGS__) extern "C"{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavcodec/jni.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
}
#include<iostream>
using namespace std; static double r2d(AVRational r)
{
return r.num==||r.den == ? :(double)r.num/(double)r.den;
} //当前时间戳 clock
long long GetNowMs()
{
struct timeval tv;
gettimeofday(&tv,NULL);
int sec = tv.tv_sec%;
long long t = sec*+tv.tv_usec/;
return t;
}
extern "C"
JNIEXPORT
jint JNI_OnLoad(JavaVM *vm,void *res)
{
av_jni_set_java_vm(vm,);
return JNI_VERSION_1_4;
} extern "C"
JNIEXPORT jstring
JNICALL
Java_aplay_testffmpeg_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++ ";
// TODO
hello += avcodec_configuration();
return env->NewStringUTF(hello.c_str());
} extern "C"
JNIEXPORT void JNICALL
Java_aplay_testffmpeg_XPlay_Open(JNIEnv *env, jobject instance, jstring url_, jobject surface) {
const char *path = env->GetStringUTFChars(url_, ); //初始化解封装
av_register_all();
//初始化网络
avformat_network_init(); avcodec_register_all(); //打开文件
AVFormatContext *ic = NULL;
//char path[] = "/sdcard/video.flv";
int re = avformat_open_input(&ic,path,,);
if(re != )
{
LOGW("avformat_open_input failed!:%s",av_err2str(re));
return;
}
LOGW("avformat_open_input %s success!",path);
//获取流信息
re = avformat_find_stream_info(ic,);
if(re != )
{
LOGW("avformat_find_stream_info failed!");
}
LOGW("duration = %lld nb_streams = %d",ic->duration,ic->nb_streams); int fps = ;
int videoStream = ;
int audioStream = ; for(int i = ; i < ic->nb_streams; i++)
{
AVStream *as = ic->streams[i];
if(as->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
{
LOGW("视频数据");
videoStream = i;
fps = r2d(as->avg_frame_rate); LOGW("fps = %d,width=%d height=%d codeid=%d pixformat=%d",fps,
as->codecpar->width,
as->codecpar->height,
as->codecpar->codec_id,
as->codecpar->format
);
}
else if(as->codecpar->codec_type ==AVMEDIA_TYPE_AUDIO )
{
LOGW("音频数据");
audioStream = i;
LOGW("sample_rate=%d channels=%d sample_format=%d",
as->codecpar->sample_rate,
as->codecpar->channels,
as->codecpar->format
);
}
}
//ic->streams[videoStream];
//获取音频流信息
audioStream = av_find_best_stream(ic,AVMEDIA_TYPE_AUDIO,-,-,NULL,);
LOGW("av_find_best_stream audioStream = %d",audioStream);
//////////////////////////////////////////////////////////
//打开视频解码器
//软解码器
AVCodec *codec = avcodec_find_decoder(ic->streams[videoStream]->codecpar->codec_id);
//硬解码
codec = avcodec_find_decoder_by_name("h264_mediacodec");
if(!codec)
{
LOGW("avcodec_find failed!");
return;
}
//解码器初始化
AVCodecContext *vc = avcodec_alloc_context3(codec);
avcodec_parameters_to_context(vc,ic->streams[videoStream]->codecpar); vc->thread_count = ;
//打开解码器
re = avcodec_open2(vc,,);
//vc->time_base = ic->streams[videoStream]->time_base;
LOGW("vc timebase = %d/ %d",vc->time_base.num,vc->time_base.den);
if(re != )
{
LOGW("avcodec_open2 video failed!");
return;
} //////////////////////////////////////////////////////////
//打开音频解码器
//软解码器
AVCodec *acodec = avcodec_find_decoder(ic->streams[audioStream]->codecpar->codec_id);
//硬解码
//codec = avcodec_find_decoder_by_name("h264_mediacodec");
if(!acodec)
{
LOGW("avcodec_find failed!");
return;
}
//音频解码器初始化
AVCodecContext *ac = avcodec_alloc_context3(acodec);
avcodec_parameters_to_context(ac,ic->streams[audioStream]->codecpar);
ac->thread_count = ;
//打开解码器
re = avcodec_open2(ac,,);
if(re != )
{
LOGW("avcodec_open2 audio failed!");
return;
}
//读取帧数据
AVPacket *pkt = av_packet_alloc();
AVFrame *frame = av_frame_alloc();
long long start = GetNowMs();
int frameCount = ; //初始化像素格式转换的上下文
SwsContext *vctx = NULL;
int outWidth = ;
int outHeight = ;
char *rgb = new char[**];
char *pcm = new char[**]; //音频重采样上下文初始化
SwrContext *actx = swr_alloc();
actx = swr_alloc_set_opts(actx,
av_get_default_channel_layout(),
AV_SAMPLE_FMT_S16,ac->sample_rate,
av_get_default_channel_layout(ac->channels),
ac->sample_fmt,ac->sample_rate,
, );
re = swr_init(actx);
if(re != )
{
LOGW("swr_init failed!");
}
else
{
LOGW("swr_init success!");
} //显示窗口初始化
ANativeWindow *nwin = ANativeWindow_fromSurface(env,surface);
ANativeWindow_setBuffersGeometry(nwin,outWidth,outHeight,WINDOW_FORMAT_RGBA_8888);
ANativeWindow_Buffer wbuf; for(;;)
{
//超过三秒
if(GetNowMs() - start >= )
{
LOGW("now decode fps is %d",frameCount/);
start = GetNowMs();
frameCount = ;
} int re = av_read_frame(ic,pkt);
if(re != )
{ LOGW("读取到结尾处!");
int pos = * r2d(ic->streams[videoStream]->time_base);
av_seek_frame(ic,videoStream,pos,AVSEEK_FLAG_BACKWARD|AVSEEK_FLAG_FRAME );
continue;
} AVCodecContext *cc = vc;
if(pkt->stream_index == audioStream)
cc=ac; //发送到线程中解码
re = avcodec_send_packet(cc,pkt);
//清理
int p = pkt->pts;
av_packet_unref(pkt); if(re != )
{
LOGW("avcodec_send_packet failed!");
continue;
} for(;;)
{
re = avcodec_receive_frame(cc,frame);
if(re !=)
{
//LOGW("avcodec_receive_frame failed!");
break;
}
//LOGW("avcodec_receive_frame %lld",frame->pts);
//如果是视频帧
if(cc == vc)
{
frameCount++;
vctx = sws_getCachedContext(vctx,
frame->width,
frame->height,
(AVPixelFormat)frame->format,
outWidth,
outHeight,
AV_PIX_FMT_RGBA,
SWS_FAST_BILINEAR,
,,
);
if(!vctx)
{
LOGW("sws_getCachedContext failed!");
}
else
{
uint8_t *data[AV_NUM_DATA_POINTERS] = {};
data[] =(uint8_t *)rgb;
int lines[AV_NUM_DATA_POINTERS] = {};
lines[] = outWidth * ;
int h = sws_scale(vctx,
(const uint8_t **)frame->data,
frame->linesize,,
frame->height,
data,lines);
LOGW("sws_scale = %d",h);
if(h > )
{
ANativeWindow_lock(nwin,&wbuf,);
uint8_t *dst = (uint8_t*)wbuf.bits;
memcpy(dst,rgb,outWidth*outHeight*);
ANativeWindow_unlockAndPost(nwin);
}
} }
else //音频
{
uint8_t *out[] = {};
out[] = (uint8_t*) pcm; //音频重采样
int len = swr_convert(actx,out,
frame->nb_samples,
(const uint8_t**)frame->data,
frame->nb_samples);
LOGW("swr_convert = %d",len);
} } ////////////////////// }
delete rgb;
delete pcm; //关闭上下文
avformat_close_input(&ic); env->ReleaseStringUTFChars(url_, path);
}

FFmpeg(五) 重采样相关函数理解的更多相关文章

  1. FFmpeg(四) 像素转换相关函数理解

    一.基本流程 1.sws_getCachedContext();//得到像素转换的上下文 2.sws_scale()://进行转换 二.函数说明 1.SwsContext *vctx = NULL;  ...

  2. FFmpeg(三) 编解码相关函数理解

    一.编解码基本流程 主要流程: 打开视频解码器(音频一样) 软解码.硬解码 进行编解码 下面先来看打开视频解码器 ①avcodec_register_all()//初始化解码 ②先找到解码器. 找解码 ...

  3. FFmpeg(二) 解封装相关函数理解

    一.解封装基本流程 ①av_register_All()////初始化解封装,注册解析和封装的格式. ②avformat_netword_init()//初始化网络,解析rtsp协议 ③avforma ...

  4. Java提高班(五)深入理解BIO、NIO、AIO

    导读:本文你将获取到:同/异步 + 阻/非阻塞的性能区别:BIO.NIO.AIO 的区别:理解和实现 NIO 操作 Socket 时的多路复用:同时掌握 IO 最底层最核心的操作技巧. BIO.NIO ...

  5. (原)ffmpeg过滤器开发和理解

    最近学习了ffmpeg关于filter过滤器的开发,关于中间的几个相关概念,我们先放在简单介绍一下: AVFilterGraph:几乎完全等同与directShow中的fitlerGraph,代表一串 ...

  6. 《深入理解Android 卷III》第五章 深入理解Android输入系统

    <深入理解Android 卷III>即将公布.作者是张大伟.此书填补了深入理解Android Framework卷中的一个主要空白.即Android Framework中和UI相关的部分. ...

  7. Golang 入门系列(十五)如何理解go的并发?

    前面已经讲过很多Golang系列知识,感兴趣的可以看看以前的文章,https://www.cnblogs.com/zhangweizhong/category/1275863.html, 接下来要说的 ...

  8. Deep learning:四十五(maxout简单理解)

    maxout出现在ICML2013上,作者Goodfellow将maxout和dropout结合后,号称在MNIST, CIFAR-10, CIFAR-100, SVHN这4个数据上都取得了start ...

  9. FFMpeg音频重采样和视频格式转

    一.视频像素和尺寸转换函数 1.sws_getContext : 像素格式上下文  --------------->多副图像(多路视频)进行转换同时显示 2.struct SwsContext  ...

随机推荐

  1. 【强联通图 | 强联通分量】HDU 1269 迷宫城堡 【Kosaraju或Tarjan算法】

      为了训练小希的方向感,Gardon建立了一座大城堡,里面有N个房间(N<=10000)和M条通道(M<=100000),每个通道都是单向的,就是说若称某通道连通了A房间和B房间,只说明 ...

  2. Rikka with Prefix Sum(组合数学)

    Rikka with Prefix Sum 题目描述 Prefix Sum is a useful trick in data structure problems. For example, giv ...

  3. Atcoder C - +/- Rectangle(思维+构造)

    题目链接:http://agc016.contest.atcoder.jp/tasks/agc016_c 题解:挺简单的构造,很容易想到的构造方法就是(h*w)的小矩阵里其他值赋值为1,最后一个赋值为 ...

  4. 现代 JavaScript 教程到底是什么?

    手册与规范 <现代 JavaScript 教程>是开源的现代 JavaScript 从入门到进阶的优质教程,它旨在帮助你逐渐掌握 JavaScript 这门语言.但是一旦你已经熟悉了这门语 ...

  5. CSS3 01. CSS3现状、属性选择器、伪类选择器、结构伪类、伪元素选择器、颜色、文本阴影shadow、盒子模型、私有化前缀

    CSS 3 现状 兼容性差,需添加私有前缀/移动端优于PC端/不断改进中/渐进增强原则/考虑用户群体/遵照产品的方案 : CSS3手册 需要阅读其--阅读及使用指引 []表示全部的可选项 || 或者 ...

  6. Erlang模块gen_fsm翻译

    模块摘要     通用有限状态机行为.   描述     用于实现有限状态机的行为模块.使用该模块实现的通用有限状态机进程(gen_fsm)将具有一组标准的接口函数,并包括用于跟踪和错误报告的功能.它 ...

  7. EditPlus5.0破解激活

    永久激活用户名激活码: 用户名:Vovan注册码:3AG46-JJ48E-CEACC-8E6EW-ECUAW 然后重启软件即可

  8. java架构之路-(源码)mybatis执行流程源码解析

    这次我们来说说Mybatis的源码,这里只说执行的流程,内部细节太多了,这里只能授之以渔了.还是最近的那段代码,我们来回顾一下. package mybatis; import mybatis.bea ...

  9. C++ 基础中的基础 ---- 引用

    C++ 基础中的基础 ---- 引用 引用的概念:引用变量是一个别名,也就是说,它是某个已存在变量的另一个名字.一旦把引用初始化为某个变量,就可以使用该引用名称或变量名称来指向变量.比如: int n ...

  10. NOIP2006 1.明明的随机数

    题目:明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了N个1到1000之间的随机整数(N≤100),对于其中重复的数字,只保留一个,把其余相同的数去掉,不同的数对应着不 ...