一、重采样流程

  重采样(解码音频数据之后格式不可以直接播放,需要重采样,类似图像的像素转换)
    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==0||r.den == 0 ? 0 :(double)r.num/(double)r.den;
}//当前时间戳 clock
long long GetNowMs()
{struct timeval tv;gettimeofday(&tv,NULL);int sec = tv.tv_sec%360000;long long t = sec*1000+tv.tv_usec/1000;return t;
}
extern "C"
JNIEXPORT
jint JNI_OnLoad(JavaVM *vm,void *res)
{av_jni_set_java_vm(vm,0);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++ ";// TODOhello += 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_, 0);//初始化解封装
    av_register_all();//初始化网络
    avformat_network_init();avcodec_register_all();//打开文件AVFormatContext *ic = NULL;//char path[] = "/sdcard/video.flv";int re = avformat_open_input(&ic,path,0,0);if(re != 0){LOGW("avformat_open_input failed!:%s",av_err2str(re));return;}LOGW("avformat_open_input %s success!",path);//获取流信息re = avformat_find_stream_info(ic,0);if(re != 0){LOGW("avformat_find_stream_info failed!");}LOGW("duration = %lld nb_streams = %d",ic->duration,ic->nb_streams);int fps = 0;int videoStream = 0;int audioStream = 1;for(int i = 0; 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,-1,-1,NULL,0);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 = 8;//打开解码器re = avcodec_open2(vc,0,0);//vc->time_base = ic->streams[videoStream]->time_base;LOGW("vc timebase = %d/ %d",vc->time_base.num,vc->time_base.den);if(re != 0){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 = 8;//打开解码器re = avcodec_open2(ac,0,0);if(re != 0){LOGW("avcodec_open2  audio failed!");return;}//读取帧数据AVPacket *pkt = av_packet_alloc();AVFrame *frame = av_frame_alloc();long long start = GetNowMs();int frameCount = 0;//初始化像素格式转换的上下文SwsContext *vctx = NULL;int outWidth = 1280;int outHeight = 720;char *rgb = new char[1920*1080*4];char *pcm = new char[48000*4*2];//音频重采样上下文初始化SwrContext *actx = swr_alloc();actx = swr_alloc_set_opts(actx,av_get_default_channel_layout(2),AV_SAMPLE_FMT_S16,ac->sample_rate,av_get_default_channel_layout(ac->channels),ac->sample_fmt,ac->sample_rate,0,0 );re = swr_init(actx);if(re != 0){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 >= 3000){LOGW("now decode fps is %d",frameCount/3);start = GetNowMs();frameCount = 0;}int re = av_read_frame(ic,pkt);if(re != 0){LOGW("读取到结尾处!");int pos = 20 * 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 != 0){LOGW("avcodec_send_packet failed!");continue;}for(;;){re = avcodec_receive_frame(cc,frame);if(re !=0){//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,0,0,0);if(!vctx){LOGW("sws_getCachedContext failed!");}else{uint8_t *data[AV_NUM_DATA_POINTERS] = {0};data[0] =(uint8_t *)rgb;int lines[AV_NUM_DATA_POINTERS] = {0};lines[0] = outWidth * 4;int h = sws_scale(vctx,(const uint8_t **)frame->data,frame->linesize,0,frame->height,data,lines);LOGW("sws_scale = %d",h);if(h > 0){ANativeWindow_lock(nwin,&wbuf,0);uint8_t *dst = (uint8_t*)wbuf.bits;memcpy(dst,rgb,outWidth*outHeight*4);ANativeWindow_unlockAndPost(nwin);}}}else //音频
            {uint8_t *out[2] = {0};out[0] = (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);
}

View Code

转载于:https://www.cnblogs.com/ZeGod/p/9995276.html

FFmpeg(五) 重采样相关函数理解相关推荐

  1. 【Android FFMPEG 开发】FFMPEG 音频重采样 ( 初始化音频重采样上下文 SwrContext | 计算音频延迟 | 计算输出样本个数 | 音频重采样 swr_convert )

    文章目录 I . FFMPEG 播放视频流程 II . FFMPEG 音频重采样流程 III . FFMPEG 音频重采样 IV . FFMPEG 初始化音频重采样上下文 SwrContext V . ...

  2. 利用 ffmpeg swr_convert重采样

    利用 ffmpeg swr_convert重采样 CResample::CResample(int input_channels, int input_rate, int output_channel ...

  3. ffmpeg音频重采样

    音频重采样 重采样就是改变音频的采样率.sample format(采样格式).声道数(channel)等参数 为什么需要重采样? 1.音频重采样是为了将音频统一格式 比如直播: 麦克风采集 44.1 ...

  4. 深入java核心_Java核心(五)深入理解BIO、NIO、AIO

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

  5. Java核心(五)深入理解BIO、NIO、AIO

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

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

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

  7. 人工智能目标检测总结(五)——深入理解one-stage目标检测模型

    本文翻译自One-shot object detection,原作者保留版权. 作为计算机视觉领域的一项重要任务,目标检测是要找到一张图片里的感兴趣物体: 这比图像分类任务更高级,因为分类只需要告诉图 ...

  8. ffmpeg 音频重采样

    什么是重采样? 所谓的重采样,就是改变⾳频的采样率.sampleformat.声道数等参数,使之按照我们期望的参数输出. 为什么要重采样?  为什么要重采样?当然是原有的⾳频参数不满⾜我们的需求,⽐如 ...

  9. [深入理解Android卷一全文-第五章]深入理解常见类

    由于<深入理解Android 卷一>和<深入理解Android卷二>不再出版,而知识的传播不应该因为纸质媒介的问题而中断,所以我将在CSDN博客中全文转发这两本书的全部内容. ...

最新文章

  1. Java编程的逻辑 (39) - 剖析LinkedList
  2. P - The Shortest Path in Nya Graph HDU - 4725
  3. pythonwrite连续写入_python文件写入write()的操作
  4. STM32F103单片机ADC功能使用
  5. 0201 0402 0603 0805 1206焊盘封装尺寸
  6. 判断一个数是否为素数常见的四种方法
  7. 微信Windows版如何从旧电脑迁移聊天记录到新电脑
  8. nginx做反向代理网站加载验证码图片不出来
  9. 减少域名DNS解析时间将网页加载速度提升新层次
  10. 英特尔处理器后缀字母的意思
  11. 五分钟学Java:一篇文章带你搞懂spring全家桶套餐
  12. pip3 install -U qcloud-python-sts 安装失败解决方法
  13. 小红书的浏览量很低是为什么?有什么提高的方法吗?
  14. Python批量重命名图像
  15. Office 365平台及其价值主张
  16. SDS很好,但处理器需“减负”!
  17. 添加列、删除列的sql
  18. 硬盘检测工具HARD DISK SENTINEL PRO(硬盘哨兵)v5.70便携版
  19. 转载一位老码农的技术理想
  20. 图像分割经典论文调研:DilatedNet、DeepLabV2、HDC/DUC

热门文章

  1. 500元辛苦费,求一C#算法,自由定义表达式
  2. python—函数实例一
  3. 工具类:关于如何找到两个List数组中不同的数据的算法!
  4. 2017 年 VR 将走的 3 个方向 你更认可哪一个?
  5. 剑指offer 二进制1中的个数
  6. 差异与阵列和阵列结构和链表的区别
  7. 后缀为PDF的文件要用什么工具才能打开?
  8. 5G NGC — 关键技术 — 网络切片 — 切片的运维与运营
  9. 互联网协议 — TLS — SNI
  10. IPv6 — 移动性支持