ffmpeg多執行緒本地mp4 rtmp推流,h264+aac編碼
程式說明:使用了c++11的std執行緒,鎖,訊號量等東西,替換了pthread多執行緒。主要之前用windows下移植的linux發現多執行緒始終有問題,所以決定用原生的試試。不過現在想來,應該問題還是我佇列的設計問題。主要這裡有個坑,就是c語言for迴圈內部的區域性變數的記憶體地址是不變的,所以如果在for迴圈裡面給指標賦值,一定要特別注意。
這次的程式編寫過程中遇到很多坑。malloc生產的avframe,不要用av_frame_free銷燬。av_frame_free要和av_frame_alloc對應使用。否則會報錯。這挺奇葩的。所以avframe的釋放,還有avpacket的釋放,最好先不要寫,先不要理會記憶體洩漏,先保證程式執行起來。否則有可能你某個地方寫了free,你的encode方法或者decode方法就莫名其妙的崩潰。說莫名其妙,是因為我暫時還不清楚為什麼會這樣。而且avframe,avpacket,buffer 能夠搞全域性變數的,儘量不要搞區域性變數。
程式實現了mp4重新編碼h264+aac,然後推流。主要要控制推流速度,然後av_read_frame不能過快,之前用雙鏈表實現的佇列,弊端就是讀的速度要自己再控制。不然記憶體會很快爆滿。所以現在用的迴圈佇列實現,可以保證後期生產者和消費者的消耗速度是1:1。
還有一些奇怪的問題,現在音訊轉碼用的AVFilter,本來視訊也用的AVFilter,但是發現視訊的不好使,測試發現某些MP4,執行過程中會av_buffersrc_add_frame_flags會失敗,這個暫時不清楚什麼原因造成的。如果有知道原因的歡迎私信我。所以視訊轉碼換成了SwsContext實現,其實這個更方便,程式碼量更小。
程式現在還有一些問題,就是視訊播放初期,音視訊會有幾幀丟幀。也希望大家能解惑。
上程式碼
//loopq.h
#include <stdio.h>
#include <malloc.h>
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include<Windows.h>
using namespace std;
extern "C"{
#include <libavcodec/avcodec.h>
};
typedef struct _Queue Queue;
struct _Queue{
int size;
//存放AVFrame*的二維指標
AVFrame** tab;
int type;//1表示視訊。2表示音訊
int read_index;
int write_index;
mutex mtx;
condition_variable cond_not_full;// 指示產品緩衝區不為滿
condition_variable cond_not_empty;// 指示產品緩衝區不為空
};
void queue_init(Queue *queue, int size,int type);
void queue_push(Queue *queue, AVFrame* frame);
AVFrame* queue_pop(Queue *queue, int finished);
//dbt_rtmp.h
#include <stdint.h>
#include <malloc.h>
#include <windows.h>
#include <loopq.h>
#include <string>
extern "C"
{
#include "libavformat/avformat.h"
#include <libavutil/time.h>
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
#include "libavutil/audio_fifo.h"
#include "libavfilter/avfiltergraph.h"
#include "libavfilter/avcodec.h"
#include "libavfilter/buffersink.h"
#include "libavfilter/buffersrc.h"
#include "libavutil/avutil.h"
#include "libavutil/opt.h"
#include "libavutil/pixdesc.h"
};
#define STREAM_FRAME_RATE 25
#define INPUTURL "yekong.mp4"
//#define OUTPUTURL "pingfan_out.mp4"
#define OUTPUTURL "rtmp://localhost:1935/live/stream"
int width, height;
AVFormatContext *ifmt_ctx = NULL;
AVStream* ist_v = NULL, *ist_a = NULL;
AVFormatContext* ofmt_ctx = NULL;
AVCodecContext *audio_codec_context = NULL, *video_codec_context = NULL;
AVCodec* video_codec = NULL, *audio_codec = NULL;
AVStream *video_st = NULL, *audio_st = NULL;
int videoframecnt = 1;
int audioframecnt;
SwsContext *sws_ctx = NULL;
uint8_t *video_data_buffer = NULL;
int finished;
double audio_clock,start_time;
//video param
AVCodecID video_codecID = AV_CODEC_ID_H264;
AVPacket venc_pkt;
AVFrame *video_filt_frame = NULL;
AVFrame* videosrcFrame = NULL;
AVPacket aenc_pkt;
AVFrame *audio_filt_frame = NULL;
AVFrame* audiosrcFrame = NULL;
//audio param
int dst_channels = 2; //聲道
AVCodecID audio_codecID = AV_CODEC_ID_AAC;
int audio_frame_size = 1024;
AVBitStreamFilterContext * m_aac_adtstoasc; //aac->adts to asc過濾器
int out_framesize; //音訊輸出流的每幀取樣數(aac為1024)
//輸入流中音視訊的索引
int iv_index = -1, ia_index = -1;
Queue audioq;
Queue videoq;;
int64_t last_video_pts;
int64_t last_audio_pts;
void init_packet(AVPacket *packet);
void add_stream(AVFormatContext *out_format_context, AVStream** st, AVCodecContext **out_codec_context, AVCodec** codec, AVCodecID codec_id);
void open_video(AVCodecContext* codec_context, AVCodec* codec);
void open_audio(AVCodecContext* audio_codec_context, AVCodec * codec);
int encode_video_frame(AVFrame *frame,AVFormatContext *out_format_context,AVStream *video_st);
int encode_audio_frame(AVFrame *frame, int nbsamples,AVFormatContext *output_format_context, AVStream* st);
void decode_video_frame(AVPacket *pkt);
void decode_audio_frame(AVPacket *pkt);
typedef struct FilteringContext {
AVFilterContext *buffersink_ctx;
AVFilterContext *buffersrc_ctx;
AVFilterGraph *filter_graph;
} FilteringContext;
FilteringContext *filter_ctx;
//loopq.cpp
#include <loopq.h>
void queue_init(Queue* queue,int size,int type){
queue->size = size;
queue->read_index = 0;
queue->write_index = 0;
queue->type = type;
queue->tab = (AVFrame**)malloc(sizeof(AVFrame*)* size);
int i;
for (i = 0; i<size; i++){
queue->tab[i] = (AVFrame*)malloc(sizeof(AVFrame));
}
}
void queue_push(Queue *queue, AVFrame* frame) {
unique_lock<mutex> lock(queue->mtx);
//cout << "生產者thread_id:" << this_thread::get_id() << endl;
while (((queue->write_index + 1) % queue->size) == queue->read_index) {
printf("%d籃子現在是滿的,等待消費者騰出一個位置\n",queue->type);
/*for (int i = 0; i < 12; i++){
printf("%d-->%d\n", i, ((AVFrame*)(queue->tab[i]))->pts);
}*/
queue->cond_not_full.wait(lock); // 生產者等待"產品庫緩衝區不為滿"這一條件發生.
}
if (queue->tab[queue->write_index] == NULL){
queue->tab[queue->write_index] = (AVFrame*)malloc(sizeof(AVFrame));
}
*(queue->tab[queue->write_index]) = *frame;
printf("%d通知消費者%d這個位置現在有產品pts:%d了\n", queue->type, queue->write_index, ((AVFrame*)(queue->tab[queue->write_index]))->pts);
queue->write_index++; // 寫入位置後移.
if (queue->write_index >= queue->size) // 寫入位置若是在佇列最後則重新設定為初始位置.
queue->write_index = 0;
queue->cond_not_empty.notify_all();// 通知消費者產品庫不為空.
lock.unlock();
}
AVFrame* queue_pop(Queue *queue, int finished) {
unique_lock<mutex> lock(queue->mtx);
//cout << "消費者thread_id:" << this_thread::get_id() << endl;
while (queue->read_index == queue->write_index) {
if (finished){
printf("%d消費者等待%d這個位置填充產品,但是此時已經沒有資料了\n", queue->type,queue->read_index);
lock.unlock();
return NULL;
}
printf("%d消費者等待%d這個位置填充產品\n", queue->type, queue->read_index);
queue->cond_not_empty.wait(lock); // 消費者等待"產品庫緩衝區不為空"這一條件發生.
}
int idx = queue->read_index;
printf("%d消費者在%d這個位置取出產品pts:%d\n", queue->type, queue->read_index,queue->tab[queue->read_index]->pts);
queue->read_index++;
if (queue->read_index >= queue->size) // 讀取位置若移到最後,則重新置位.
queue->read_index = 0;
printf("%d消費者在%d這個位置通知生產者產品庫不為滿,可以繼續生產了\n", queue->type, queue->read_index);
queue->cond_not_full.notify_all(); // 通知消費者產品庫不為滿.
lock.unlock();
return queue->tab[idx];
}
//dbt_rtmp.cpp
#include <dbt_rtmp.h>
void init_packet(AVPacket *packet){
av_init_packet(packet);
packet->data = NULL;
packet->size = 0;
}
void av_packet_rescale_ts(AVPacket *pkt, AVRational src_tb, AVRational dst_tb)
{
if (pkt->pts != AV_NOPTS_VALUE)
pkt->pts = av_rescale_q(pkt->pts, src_tb, dst_tb);
if (pkt->dts != AV_NOPTS_VALUE)
pkt->dts = av_rescale_q(pkt->dts, src_tb, dst_tb);
if (pkt->duration > 0)
pkt->duration = av_rescale_q(pkt->duration, src_tb, dst_tb);
}
int initAudioFilters(FilteringContext *filter_ctx, AVCodecContext * icodecContext, AVCodecContext *ocodecContext)
{
char args[512];
int ret;
AVFilter *abuffersrc = avfilter_get_by_name("abuffer");
AVFilter *abuffersink = avfilter_get_by_name("abuffersink");
AVFilterInOut *outputs = avfilter_inout_alloc();
AVFilterInOut *inputs = avfilter_inout_alloc();
AVFilterContext *buffersrc_ctx = NULL;
AVFilterContext *buffersink_ctx = NULL;
if (!icodecContext->channel_layout)
icodecContext->channel_layout = av_get_default_channel_layout(icodecContext->channels);
//AV_SAMPLE_FMT_FLTP
static const enum AVSampleFormat out_sample_fmts[] = { ocodecContext->sample_fmt, AV_SAMPLE_FMT_NONE };
static const int64_t out_channel_layouts[] = { ocodecContext->channel_layout, -1 };
static const int out_sample_rates[] = { ocodecContext->sample_rate, -1 };
AVFilterGraph* filter_graph = avfilter_graph_alloc();
filter_graph->nb_threads = 1;
sprintf_s(args, sizeof(args),
"time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%I64x",
icodecContext->time_base.num, icodecContext->time_base.den, icodecContext->sample_rate,
av_get_sample_fmt_name(icodecContext->sample_fmt), icodecContext->channel_layout);
ret = avfilter_graph_create_filter(&buffersrc_ctx, abuffersrc, "in",
args, NULL, filter_graph);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer source\n");
return ret;
}
/* buffer audio sink: to terminate the filter chain. */
ret = avfilter_graph_create_filter(&buffersink_ctx, abuffersink, "out",
NULL, NULL, filter_graph);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer sink\n");
return ret;
}
ret = av_opt_set_int_list(buffersink_ctx, "sample_fmts", out_sample_fmts, -1,
AV_OPT_SEARCH_CHILDREN);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Cannot set output sample format\n");
return ret;
}
ret = av_opt_set_int_list(buffersink_ctx, "channel_layouts", out_channel_layouts, -1,
AV_OPT_SEARCH_CHILDREN);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Cannot set output channel layout\n");
return ret;
}
ret = av_opt_set_int_list(buffersink_ctx, "sample_rates", out_sample_rates, -1,
AV_OPT_SEARCH_CHILDREN);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Cannot set output sample rate\n");
return ret;
}
/* Endpoints for the filter graph. */
outputs->name = av_strdup("in");
outputs->filter_ctx = buffersrc_ctx;;
outputs->pad_idx = 0;
outputs->next = NULL;
inputs->name = av_strdup("out");
inputs->filter_ctx =buffersink_ctx;
inputs->pad_idx = 0;
inputs->next = NULL;
if ((ret = avfilter_graph_parse_ptr(filter_graph, "anull",
&inputs, &outputs, nullptr)) < 0)
return ret;
if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0)
return ret;
av_buffersink_set_frame_size(buffersink_ctx, 1024);
/* Fill FilteringContext */
filter_ctx->buffersrc_ctx = buffersrc_ctx;
filter_ctx->buffersink_ctx = buffersink_ctx;
filter_ctx->filter_graph = filter_graph;
return 0;
}
void add_stream(AVFormatContext *out_format_context, AVStream** st, AVCodecContext **out_codec_context, AVCodec** codec, AVCodecID codec_id)
{
*codec = avcodec_find_encoder(codec_id);
if (!codec) {
fprintf(stderr, "Could not find encoder for '%s'\n",
avcodec_get_name(codec_id));
getchar();exit(1);
}
*st = avformat_new_stream(out_format_context, *codec);
if (!*st) {
fprintf(stderr, "Could not alloc stream");
getchar();exit(1);
}
*out_codec_context = (*st)->codec;
(*st)->id = out_format_context->nb_streams - 1;
(*out_codec_context)->codec_id = codec_id;
AVRational time_base;
switch ((*codec)->type) {
case AVMEDIA_TYPE_AUDIO:
(*out_codec_context)->codec_type = AVMEDIA_TYPE_AUDIO;
(*out_codec_context)->channels = dst_channels;
(*out_codec_context)->channel_layout = av_get_default_channel_layout(dst_channels);
(*out_codec_context)->sample_rate = ist_a->codec->sample_rate;
(*out_codec_context)->frame_size = audio_frame_size;
(*out_codec_context)->sample_fmt = (*codec)->sample_fmts[0];
time_base = { 1, (*out_codec_context)->sample_rate };
(*out_codec_context)->time_base = time_base;
break;
case AVMEDIA_TYPE_VIDEO:
(*out_codec_context)->codec_type = AVMEDIA_TYPE_VIDEO;
(*out_codec_context)->time_base = ist_v->codec->time_base;
(*out_codec_context)->pix_fmt = (*codec)->pix_fmts[0];
(*out_codec_context)->width = width;
(*out_codec_context)->height = height;
(*out_codec_context)->me_range = 0;
(*out_codec_context)->max_qdiff = 4;
(*out_codec_context)->qmin = ist_v->codec->qmin;
(*out_codec_context)->qmax = ist_v->codec->qmax;
(*out_codec_context)->qcompress = 0.6;
break;
default:
break;
}
(*out_codec_context)->codec_tag = 0;
// some formats want stream headers to be separate
if (out_format_context->oformat->flags & AVFMT_GLOBALHEADER)
(*out_codec_context)->flags |= CODEC_FLAG_GLOBAL_HEADER;
}
void open_video(AVCodecContext* codec_context, AVCodec* codec){
AVDictionary *param = NULL;
av_dict_set(¶m, "preset", "veryfast", 0);
av_dict_set(¶m, "tune", "zerolatency", 0);
if (avcodec_open2(video_st->codec, codec, ¶m) < 0) {
fprintf(stderr, "could not open codec\n");
getchar(); exit(1);
}
}
void open_audio(AVCodecContext* audio_codec_context, AVCodec * codec){
if (avcodec_open2(audio_codec_context, codec, NULL) < 0) {
printf("Could not open audio codec \n");
getchar();exit(1);
}
}
int encode_video_frame(AVFrame *frame,
AVFormatContext *out_format_context,
AVStream *video_st){
AVCodecContext* out_codec_context = video_st->codec;
int got_packet;
if (frame){
//decodec層時間基到codec的時間基轉換
frame->pts = av_rescale_q(frame->pts, ist_v->codec->time_base, video_st->codec->time_base);
frame->pict_type = AV_PICTURE_TYPE_NONE;
}
int ret = avcodec_encode_video2(out_codec_context, &venc_pkt,
frame, &got_packet);
if (ret < 0 || !got_packet){ //在flush的時候,如果失敗 ,說明丟失幀(快取幀)已經空了
return 1;
}
//codec層時間基轉mux層
av_packet_rescale_ts(&venc_pkt, video_st->codec->time_base, video_st->time_base);
venc_pkt.stream_index = video_st->index;
printf("video info--- enc_pkt:pts:%lld\t dts:%lld\t duration:%d\n", venc_pkt.pts, venc_pkt.dts, venc_pkt.duration);
last_video_pts = venc_pkt.pts;
ret = av_interleaved_write_frame(out_format_context, &venc_pkt);
if (ret < 0){
printf("write video frame failed!\n");
return 1;
}
else{
printf("write video frame success\t%d\n", videoframecnt);
videoframecnt++;
}
return 0;
}
int encode_audio_frame(AVFrame *frame, int nbsamples,
AVFormatContext *output_format_context, AVStream* st){
int got_packet;
if (frame){
//decodec層時間基到codec的時間基轉換
frame->pts = av_rescale_q(frame->pts, ist_a->codec->time_base, audio_st->codec->time_base);
}
int ret = avcodec_encode_audio2(st->codec, &aenc_pkt,
frame, &got_packet);
if (ret < 0 || !got_packet){
return 1;
}
av_packet_rescale_ts(&aenc_pkt, audio_st->codec->time_base, audio_st->time_base);
aenc_pkt.stream_index = audio_st->index;
last_audio_pts = aenc_pkt.pts;
//printf("audio info--- enc_pkt:pts:%lld\t dts:%lld\t duration:%d\n", aenc_pkt.pts, aenc_pkt.dts, aenc_pkt.duration);
av_bitstream_filter_filter(m_aac_adtstoasc, audio_st->codec, NULL, &aenc_pkt.data, &aenc_pkt.size, aenc_pkt.data, aenc_pkt.size, 0);
ret = av_interleaved_write_frame(output_format_context, &aenc_pkt);
if (ret < 0){
printf("write audio frame failed!\n");
return 1;
}
else{
audioframecnt++;
// printf("write audio frame success!\t%d\n", audioframecnt);
}
return 0;
}
void decode_video_frame(AVPacket *pkt){
av_packet_rescale_ts(pkt, ist_v->time_base, ist_v->codec->time_base);
int got_picture;
avcodec_decode_video2(ist_v->codec, videosrcFrame, &got_picture, pkt);
printf("解析視訊called,got_picture:%d\n", got_picture);
if (got_picture){
videosrcFrame->pts = av_frame_get_best_effort_timestamp(videosrcFrame);
avpicture_fill((AVPicture *)video_filt_frame, video_data_buffer, video_codec_context->pix_fmt, video_codec_context->width, video_codec_context->height);
sws_scale(sws_ctx, videosrcFrame->data, videosrcFrame->linesize, 0, height, video_filt_frame->data, video_filt_frame->linesize);
video_filt_frame->pts = videosrcFrame->pts;
queue_push(&videoq, video_filt_frame);
printf("放入了視訊\n");
}
}
void decode_audio_frame(AVPacket *pkt){
//demux層轉decode層時間基
av_packet_rescale_ts(pkt, ist_a->time_base, ist_a->codec->time_base);
int got_frame;
avcodec_decode_audio4(ist_a->codec, audiosrcFrame, &got_frame, pkt);
printf("解析音訊called,got_frame:%d\n", got_frame);
if (got_frame){
audiosrcFrame->pts = av_frame_get_best_effort_timestamp(audiosrcFrame);
if (av_buffersrc_add_frame_flags(filter_ctx[ia_index].buffersrc_ctx,
audiosrcFrame, AV_BUFFERSRC_FLAG_PUSH) >= 0){
while (1) {
int ret = av_buffersink_get_frame_flags(filter_ctx[ia_index].buffersink_ctx,
audio_filt_frame, AV_BUFFERSINK_FLAG_NO_REQUEST);
if (ret < 0) {
if (ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) {
printf("audio Error in av_buffersink_get_frame_flags\n");
}
break;
}
queue_push(&audioq, audio_filt_frame);
}
}
else{
printf("audio av_buffersrc_add_frame_flags failed");
}
}
}
void read_decode_thread(int arg){
int ret;
AVPacket pkt;
init_packet(&pkt);
for (;;){
ret = av_read_frame(ifmt_ctx, &pkt);
if (ret < 0){
printf("到檔案尾了\n");
finished = 1;
break;
}
if (pkt.stream_index == iv_index){
printf("開始解析視訊\n");
decode_video_frame(&pkt);
}
else if (pkt.stream_index == ia_index){
printf("開始解析音訊\n");
decode_audio_frame(&pkt);
}
}
av_free_packet(&pkt);
}
void encode_thread(int arg){
AVFrame *pframe = av_frame_alloc();
AVFrame* frame = NULL;
for (;;){
if (av_compare_ts(last_audio_pts, audio_st->time_base, last_video_pts, video_st->time_base) <= 0){
printf("現在去取音訊\n");
frame = queue_pop(&audioq, finished);
if (frame == NULL){
printf("audio queue_pop exit\n");
break;
}
printf("audio frame----%x,pts:%d\n", &frame, frame->pts);
double delay = (double)out_framesize / audio_st->codec->sample_rate;
audio_clock += delay;
double audiodiff = audio_clock - (double)av_gettime()/1000000;
if (audiodiff > 0){
Sleep(audiodiff*1000);
}
*pframe = *frame;
encode_audio_frame(frame, out_framesize, ofmt_ctx, audio_st);
}
else{
printf("現在去取視訊\n");
frame = queue_pop(&videoq, finished);
if (frame == NULL){
printf("video queue_pop exit\n");
break;
}
printf("video frame----%x,pts:%d\n", &frame, frame->pts);
double ptstime = last_video_pts*av_q2d(video_st->time_base);
double videodiff = start_time+ptstime - audio_clock;
if (videodiff > 0){
Sleep(videodiff * 1000);
}
*pframe = *frame;
encode_video_frame(pframe, ofmt_ctx, video_st);
}
}
av_frame_free(&pframe);
}
int main(int argc, char **argv){
av_register_all();
avformat_network_init();
avfilter_register_all();
int ret;
AVDictionary* in_options = NULL;
//av_dict_set(&in_options, "re", "1", 0);
if ((ret = avformat_open_input(&ifmt_ctx, INPUTURL, 0, &in_options)) < 0) {
printf("Could not open input file.");
}
avformat_find_stream_info(ifmt_ctx, 0);
for (int i = 0; i < ifmt_ctx->nb_streams; i++) {
if (ifmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO){
iv_index = i;
ist_v = ifmt_ctx->streams[i];
width = ist_v->codec->width;
height = ist_v->codec->height;
AVCodec *codec = avcodec_find_decoder(ist_v->codec->codec_id);
/* open the codec */
if (avcodec_open2(ist_v->codec, codec,NULL) < 0) {
fprintf(stderr, "could not open input video decoder codec\n");
getchar();exit(1);
}
}
else if (ifmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO){
ia_index = i;
ist_a = ifmt_ctx->streams[i];
AVCodec *codec = avcodec_find_decoder(ist_a->codec->codec_id);
/* open the codec */
if (avcodec_open2(ist_a->codec, codec, NULL) < 0) {
fprintf(stderr, "could not open input audio decoder codec\n");
getchar(); exit(1);
}
}
}
av_dump_format(ifmt_ctx, 0, INPUTURL, 0);
ofmt_ctx = avformat_alloc_context();
if (strstr(OUTPUTURL, "rtmp")){
avformat_alloc_output_context2(&ofmt_ctx, NULL, "flv", OUTPUTURL); //RTMP
}
else{
avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, OUTPUTURL);
}
AVOutputFormat* fmt = ofmt_ctx->oformat;
if (!fmt) {
fprintf(stderr, "Could not find suitable output format");
getchar();exit(1);
}
add_stream(ofmt_ctx, &video_st, &video_codec_context, &video_codec, video_codecID);
add_stream(ofmt_ctx, &audio_st, &audio_codec_context, &audio_codec, audio_codecID);
open_video(video_codec_context, video_codec);
open_audio(audio_codec_context, audio_codec);
av_dump_format(ofmt_ctx, 0, OUTPUTURL, 1);
filter_ctx = (FilteringContext *)av_malloc_array(ifmt_ctx->nb_streams, sizeof(*filter_ctx));
initAudioFilters(&filter_ctx[ia_index], ist_a->codec, audio_st->codec);
sws_ctx = sws_getContext(
width, height, ist_v->codec->pix_fmt,
width, height, video_codec_context->pix_fmt,
SWS_BICUBIC, NULL, NULL, NULL);
video_data_buffer = new uint8_t[avpicture_get_size(video_codec_context->pix_fmt, video_codec_context->width, video_codec_context->height)];
/* open the output file, if needed */
if (!(fmt->flags & AVFMT_NOFILE)) {
ret = avio_open(&ofmt_ctx->pb, OUTPUTURL, AVIO_FLAG_WRITE);
if (ret < 0) {
fprintf(stderr, "Could not open '%s': %s\n", OUTPUTURL,
"");
return 1;
}
}
init_packet(&venc_pkt);
video_filt_frame = av_frame_alloc();
videosrcFrame = av_frame_alloc();
init_packet(&aenc_pkt);
audio_filt_frame = av_frame_alloc();
audiosrcFrame = av_frame_alloc();
queue_init(&audioq,50,2);
queue_init(&videoq,50,1);
m_aac_adtstoasc = av_bitstream_filter_init("aac_adtstoasc");
/*AVDictionary *out_options = NULL;
av_dict_set(&out_options, "rtmp_buffer", "1024000", 0);
av_dict_set(&out_options, "max_delay", "500000", 0);
av_dict_set(&out_options, "timeout", "6", 0);*/
ret = avformat_write_header(ofmt_ctx, NULL);
if (ret < 0) {
fprintf(stderr, "Error occurred when opening output file: %s\n", "");
return 1;
}
out_framesize = audio_codec_context->frame_size;
audio_clock = start_time=(double)av_gettime() / 1000000;
thread t1(read_decode_thread, NULL);
thread t2(encode_thread, NULL);
t1.join();
t2.join();
if (video_codec_context->codec->capabilities &CODEC_CAP_DELAY){
while (!encode_video_frame(NULL, ofmt_ctx, video_st)){
printf("encode_video_frame while");
;
}
}
if (audio_codec_context->codec->capabilities &CODEC_CAP_DELAY){
while (!encode_audio_frame(NULL, out_framesize, ofmt_ctx,audio_st)){
printf("encode_audio_frame while");
;
}
}
av_write_trailer(ofmt_ctx);
av_bitstream_filter_close(m_aac_adtstoasc);
avformat_close_input(&ifmt_ctx);
av_free_packet(&venc_pkt);
av_frame_free(&video_filt_frame);
av_frame_free(&videosrcFrame);
sws_freeContext(sws_ctx);
if (ofmt_ctx) {
avio_closep(&ofmt_ctx->pb);
avformat_free_context(ofmt_ctx);
}
printf("程式執行end");
return getchar();
}