代码实现
#include <thread>
#include <iostream>
#include <fstream>
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
}
int mp4toannexb(AVBSFContext* bsf_ctx, AVPacket *pkt, std::ofstream& out)
{
int ret;
ret = av_bsf_send_packet(bsf_ctx, pkt);
if (ret < 0) {
std::cout << "bsf send packet failed, errno:" << ret << std::endl;
return -1;
}
for(;;) {
ret = av_bsf_receive_packet(bsf_ctx, pkt);
if (AVERROR_EOF == ret || AVERROR(EAGAIN) == ret) {
return 0;
}
if (ret < 0) {
std::cout << "Could not receive packet, errno:" << ret << std::endl;
return -1;
}
out.write((const char*)pkt->data, pkt->size);
}
return 0;
}
int find_sample_index(int samplerate)
{
const int adts_sample_rates[16] = {
96000,
88200,
64000,
48000,
44100,
32000,
24000,
22050,
16000,
12000,
11025,
8000,
7350,
-1,
-1,
-1,
};
for(int i=0; i < 16;i++)
{
if(samplerate == adts_sample_rates[i])
return i;
}
return 15;
}
int main()
{
AVOutputFormat *ofmt = NULL;
AVFormatContext *ifmt_ctx = NULL;
AVBSFContext *bsf_ctx = NULL;
AVPacket *pkt = NULL;
const char *in_filename = "rtmp://vlive2018.people.com.cn/2010/cctv132019/live_2000";
int ret = -1;
int audio_index = -1;
int video_index = -1;
bool stop = false;
std::ofstream outh264("out.h264", std::ios::binary | std::ios::trunc);
std::ofstream outaac("out.aac", std::ios::binary | std::ios::trunc);
// 初始化网络
avformat_network_init();
// 初始化输入格式上下文
if ((ifmt_ctx = avformat_alloc_context()) == NULL) {
std:: cout << "avformat_alloc_context failed." << std::endl;
exit(1);
}
// 打开输入格式上下文
if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) {
std:: cout << "Could not open input file." << std::endl;
exit(1);
}
// 获取输入信息
if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {
std:: cout << "Failed to retrieve input stream information" << std::endl;
return -1;
}
// 申请pkt
if (!(pkt = av_packet_alloc())) {
std:: cout << "Could not allocate packet"<< std::endl;
return -1;
}
audio_index = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
if (audio_index < 0) {
std:: cout << "Could not find stream " << std::string(av_get_media_type_string(AVMEDIA_TYPE_AUDIO)) << std::endl;
return -1;
}
video_index = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
if (video_index < 0) {
std:: cout << "Could not find stream " << std::string(av_get_media_type_string(AVMEDIA_TYPE_VIDEO)) << std::endl;
return -1;
}
av_dump_format(ifmt_ctx, 0, in_filename, 0);
const AVBitStreamFilter *filter = av_bsf_get_by_name("h264_mp4toannexb");
if (NULL == filter) {
std:: cout << "Could not create filter" << std::endl;
return -1;
}
ret = av_bsf_alloc(filter, &bsf_ctx);
if (ret < 0) {
printf("Could not alloc bitstream filter \n");
return -1;
}
// avcodec_parameters_from_context
ret = avcodec_parameters_copy(bsf_ctx->par_in, ifmt_ctx->streams[video_index]->codecpar);
if (ret < 0) {
printf("Parameter copy filed, errno: %d \n", ret);
return -1;
}
ret = av_bsf_init(bsf_ctx);
if (ret < 0) {
printf("BSF init failed, errno: %d \n", ret);
return -1;
}
std::thread th([&]{
AVCodecParameters *params = ifmt_ctx->streams[audio_index]->codecpar;
while (av_read_frame(ifmt_ctx, pkt) >= 0 && !stop) {
if (pkt->stream_index == video_index)
{
mp4toannexb(bsf_ctx, pkt, outh264);
}
if (pkt->stream_index == audio_index)
{
char bits[7] = {0};
int aac_frame_length = 7 + pkt->size;
int sample_index = find_sample_index(params->sample_rate);
int channels = params->channels;
if (channels == 8) {
channels = 7;
}
bits[0] = 0xff;
bits[1] = 0xf1;
bits[2] = (params->profile << 6);
bits[2] |= (sample_index << 2);
bits[2] |= (channels >> 2);
bits[3] |= ((channels << 6) & 0xC0);
bits[3] |= (aac_frame_length >> 11);
bits[4] = ((aac_frame_length >> 3) & 0xFF);
bits[5] = ((aac_frame_length << 5) & 0xE0);
bits[5] |= (0x7FF >> 6);
bits[6] = 0xfc;
outaac.write((const char*)bits, 7);
outaac.write((const char*)pkt->data, pkt->size);
}
av_packet_unref(pkt);
}
});
std::cout << "input char to stop" << std::endl;
while(getchar() != 'q');
stop = true;
if (th.joinable())
{
th.join();
}
// 释放
outh264.close();
outaac.close();
avformat_close_input(&ifmt_ctx);
av_packet_free(&pkt);
av_bsf_free(&bsf_ctx);
return 0;
}