Nginx-RTMP推流(audio)

栏目: 服务器 · Nginx · 发布时间: 6年前

内容简介:​ 推送音频跟推送视频差不多,经过数据采集,编码,然后通过RTMP推流。数据采集通常有两种方式,一种是Java层的AudioRecord,另一种是native层opensl es;采集完后就是编码,相比视频比较简单,编码库这里采用FAAC进行交叉编译,这里讲PCM的声音数据编码成AAC编码数据,什么叫AAC编码数据呢?参照维基百科:高级音频编码(Advanced Audio Coding),出现于1997年,基于MPEG-2的音频编码技术,目的是取代MP3格式。2000年,MPEG-4标准出现后,AAC重

​ 推送音频跟推送视频差不多,经过数据采集,编码,然后通过RTMP推流。数据采集通常有两种方式,一种是 Java 层的AudioRecord,另一种是native层opensl es;采集完后就是编码,相比视频比较简单,编码库这里采用FAAC进行交叉编译,这里讲PCM的声音数据编码成AAC编码数据,什么叫AAC编码数据呢?参照维基百科:

zh.wikipedia.org/wiki/進階音訊編碼

高级音频编码(Advanced Audio Coding),出现于1997年,基于MPEG-2的音频编码技术,目的是取代MP3格式。2000年,MPEG-4标准出现后,AAC重新集成了其特性,为了区别于传统的MPEG-2 AAC又称为MPEG-4 AAC。相对于mp3,AAC格式的音质更佳,文件更小。

AAC的音频文件格式有 ADIF & ADTS

Nginx-RTMP推流(audio)

​ 一种是在连续的音频数据的开始处存有解码信息,一种是在每一小段音频数据头部存放7个或者9个字节的头信息用于播放器解码。

FAAC交叉库编译

​ 了解完aac编码后,下载FAAC, jaist.dl.sourceforge.net/project/faa… 下载完成后,解压包,参照 ./configure文件进行参数配置交叉编译脚本:

#!/bin/bash

NDK_ROOT=/root/android-ndk-r17-beta2
PREFIX=`pwd`/android/armeabi-v7a

#注意  Linux  系统为 linux-x86_64, mac为 darwin-x84_64
TOOLCHAIN=$NDK_ROOT/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64
CROSS_COMPILE=$TOOLCHAIN/bin/arm-linux-androideabi

FLAGS="-isysroot $NDK_ROOT/sysroot -isystem $NDK_ROOT/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=17 -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb -Wa,--noexecstack -Wformat -Werror=format-security -std=c++11  -O0  -fPIC"

export CC="$CROSS_COMPILE-gcc --sysroot=$NDK_ROOT/platforms/android-17/arch-arm"
export CFLAGS="$FLAGS"

./configure \
--prefix=$PREFIX \
--host=arm-linux \
--with-pic \
--enable-shared=no

make clean
make install
复制代码

这里没有用Mac下编译,一直出错,改到云服务器上编译的。成功后会在 faac 的根目录下生成指定的文件夹:PREFIX= pwd /android/armeabi-v7a:

Nginx-RTMP推流(audio)

拷贝include下的头文件,lib下的静态库到项目工程中去,修改CmakeList文件,然后进行编码推流

Nginx-RTMP推流(audio)

采集—编码—推流

​ RTMP推流需要的是aac的裸数据。所以如果编码出adts格式的数据,需要去掉7个或者9个字节的adts头信息。类似于推送视频,第一个包总是包含sps和pps的音频序列包,推送音频同样第一个包是包含了接下来数据的格式的音频序列包,第一个字节定义如下:

Nginx-RTMP推流(audio)

而第二个字节为0x00与0x01,分别代表序列包与声音数据包。

Nginx-RTMP推流(audio)

数据采集

public AudioChannel(LivePusher livePusher) {
       ....
  //初始化AudioRecord。 参数:1、麦克风 2、采样率 3、声道数 4、采样位
 audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, 44100, channelConfig, AudioFormat.ENCODING_PCM_16BIT, minBufferSize > inputSamples ? minBufferSize : inputSamples);
}

//线程执行数据采集
public void startLive() {
  isLiving = true;
  executor.submit(new AudioTeask());
}

class AudioTeask implements Runnable {
        @Override
        public void run() {
            //启动录音机
            audioRecord.startRecording();
            byte[] bytes = new byte[inputSamples];
            while (isLiving) {
                int len = audioRecord.read(bytes, 0, bytes.length);
                if (len > 0) {
                    //送去编码
                    mLivePusher.native_pushAudio(bytes);
                }
            }
            //停止录音机
          audioRecord.stop();
        }
}
复制代码

AAC编码

//打开编码器
void AudioChannel::setAudioEncInfo(int samplesInHZ, int channels) {
    //打开编码器
    mChannels = channels;
    //3、一次最大能输入编码器的样本数量 也编码的数据的个数 (一个样本是16位 2字节)
    //4、最大可能的输出数据  编码后的最大字节数
    audioCodec = faacEncOpen(samplesInHZ, channels, &inputSamples, &maxOutputBytes);

    //设置编码器参数
    faacEncConfigurationPtr config = faacEncGetCurrentConfiguration(audioCodec);
    //指定为 mpeg4 标准
    config->mpegVersion = MPEG4;
    //lc 标准
    config->aacObjectType = LOW;
    //16位
    config->inputFormat = FAAC_INPUT_16BIT;
    // 编码出原始数据 既不是adts也不是adif
    config->outputFormat = 0;
    faacEncSetConfiguration(audioCodec, config);

    //输出缓冲区 编码后的数据 用这个缓冲区来保存
    buffer = new u_char[maxOutputBytes];
}


extern "C"
JNIEXPORT void JNICALL
Java_com_dongnao_pusher_live_LivePusher_native_1pushAudio(JNIEnv *env, jobject instance,
                                                          jbyteArray data_) {
    if (!audioChannel || !readyPushing) {
        return;
    }
    jbyte *data = env->GetByteArrayElements(data_, NULL);
    audioChannel->encodeData(data);
    env->ReleaseByteArrayElements(data_, data, 0);

}

//数据编码
void AudioChannel::encodeData(int8_t *data) {
    //返回编码后数据字节的长度
    int bytelen = faacEncEncode(audioCodec, reinterpret_cast<int32_t *>(data),   inputSamples, buffer,maxOutputBytes);
    if (bytelen > 0) {
        //看表
        int bodySize = 2 + bytelen;
        RTMPPacket *packet = new RTMPPacket;
        RTMPPacket_Alloc(packet, bodySize);
        //双声道
        packet->m_body[0] = 0xAF;
        if (mChannels == 1) {
            packet->m_body[0] = 0xAE;
        }
        //编码出的声音 都是 0x01
        packet->m_body[1] = 0x01;
        //图片数据
        memcpy(&packet->m_body[2], buffer, bytelen);

        packet->m_hasAbsTimestamp = 0;
        packet->m_nBodySize = bodySize;
        packet->m_packetType = RTMP_PACKET_TYPE_AUDIO;
        packet->m_nChannel = 0x11;
        packet->m_headerType = RTMP_PACKET_SIZE_LARGE;
        audioCallback(packet);
    }
}
复制代码

编码完后调用 回调audioCallback(packet),往队列中塞入数据,在start中从queue中pop data.

void callback(RTMPPacket *packet) {
    if (packet) {
        //设置时间戳
        packet->m_nTimeStamp = RTMP_GetTime() - start_time;
        //这里往队列里 塞数据,在start中 pop取数据然后发出去
        packets.push(packet);
    }
}


void *start(void *args) {
  ....
    while(readyPushing) {
      packets.pop(packet);
      if (!readyPushing) {
        break;
      }
      if (!packet) {
        continue;
      }
      // 给rtmp的流id
      packet->m_nInfoField2 = rtmp->m_stream_id;
      ....
    }
  ....
}

复制代码

这样怎个推流过程就完成了,在服务器上可以查看音频数据推流成功:

Nginx-RTMP推流(audio)

以上所述就是小编给大家介绍的《Nginx-RTMP推流(audio)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Haskell

Haskell

Simon Thompson / Addison-Wesley / 1999-3-16 / GBP 40.99

The second edition of Haskell: The Craft of Functional Programming is essential reading for beginners to functional programming and newcomers to the Haskell programming language. The emphasis is on th......一起来看看 《Haskell》 这本书的介绍吧!

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换