Created
August 31, 2018 01:30
-
-
Save moonpfe/0b81fb11d316c0e4c7b015a95f501fc3 to your computer and use it in GitHub Desktop.
AVFilter를 사용하여 오디오 샘플링 변경
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/edc-rtsp.c b/edc-rtsp.c | |
index 161ca75d..e73aecdf 100644 | |
--- a/edc-rtsp.c | |
+++ b/edc-rtsp.c | |
@@ -20,6 +20,11 @@ | |
#include <libswresample/swresample.h> | |
#include <libavutil/random_seed.h> | |
#include <libavutil/intreadwrite.h> | |
+#include <libavutil/timestamp.h> | |
+#include <libavfilter/avfilter.h> | |
+#include <libavfilter/buffersrc.h> | |
+#include <libavfilter/buffersink.h> | |
+#include <libavutil/timestamp.h> | |
#ifndef _ | |
#if defined(linux) && defined(PACKAGE) | |
@@ -71,6 +76,10 @@ struct _EdcRtspConvert | |
int output_bytes_per_sample; | |
int output_sample_rate; | |
int output_channels; | |
+ | |
+ AVFilterGraph *graph; | |
+ AVFilterContext *src; | |
+ AVFilterContext *sink; | |
}; | |
typedef enum _EdcRtspSourceType | |
@@ -109,7 +118,6 @@ struct _EdcRtspAudioOut | |
uint32_t ssrc; | |
}; | |
- | |
/** | |
* EdcRtsp object | |
*/ | |
@@ -120,6 +128,8 @@ struct _EdcRtsp | |
EdcRtspFrameRecv *frame_recv; | |
EdcRtspErrorFunc err_func; | |
+ int64_t base_timestamp; | |
+ | |
struct | |
{ | |
EdcRtspCheckExitFunc func; | |
@@ -173,6 +183,8 @@ struct _EdcRtsp | |
int width; | |
int height; | |
+ int64_t start_pts; | |
+ | |
EdcBuf *(*make_frame) (EdcRtsp *rtsp, | |
AVPacket *pkt); | |
} video; | |
@@ -182,6 +194,8 @@ struct _EdcRtsp | |
int has_stream; | |
EdcCodecID codec_id; | |
+ int64_t start_pts; | |
+ | |
EdcBuf *(*make_frame) (EdcRtsp *rtsp, | |
AVPacket *pkt); | |
/** | |
@@ -263,6 +277,171 @@ edc_rtsp_log (EdcRtsp *rtsp, | |
rtsp->transport); | |
} | |
+static int | |
+mp4serv_init_audio_resampling_filter (EdcRtsp *rtsp) | |
+{ | |
+ EdcRtspConvert *c; | |
+ const AVFilter *buffersrc; | |
+ const AVFilter *buffersink; | |
+ AVFilterInOut *outputs; | |
+ AVFilterInOut *inputs; | |
+ char args[512]; | |
+ int ret; | |
+ | |
+ c = &rtsp->audio.convert; | |
+ | |
+ c->graph = avfilter_graph_alloc (); | |
+ if (!c->graph) | |
+ { | |
+ edc_rtsp_debug (rtsp, "%s", "failed to create audio filter graph"); | |
+ return -1; | |
+ } | |
+ | |
+ buffersrc = avfilter_get_by_name ("abuffer"); | |
+ if (!buffersrc) | |
+ { | |
+ edc_rtsp_debug (rtsp, "failed to get `%s` filter", "abuffer"); | |
+ return -1; | |
+ } | |
+ | |
+ g_snprintf (args, sizeof(args), | |
+ "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%"PRIx64, | |
+ 1, c->input_sample_rate, | |
+ c->input_sample_rate, | |
+ av_get_sample_fmt_name (c->input_sample_fmt), | |
+ av_get_default_channel_layout (c->input_channels)); | |
+ | |
+ ret = avfilter_graph_create_filter (&c->src, | |
+ buffersrc, | |
+ "in", | |
+ args, | |
+ NULL, | |
+ c->graph); | |
+ if (ret < 0) | |
+ { | |
+ edc_rtsp_debug (rtsp, "failed to create `%s` filter", "abuffer"); | |
+ return -1; | |
+ } | |
+ | |
+ buffersink = avfilter_get_by_name ("abuffersink"); | |
+ if (!buffersink) | |
+ { | |
+ edc_rtsp_debug (rtsp, "failed to get `%s` filter", "abuffersink"); | |
+ return -1; | |
+ } | |
+ | |
+ ret = avfilter_graph_create_filter (&c->sink, | |
+ buffersink, | |
+ "out", | |
+ NULL, | |
+ NULL, | |
+ c->graph); | |
+ if (ret < 0) | |
+ { | |
+ edc_rtsp_debug (rtsp, "failed to create `%s` filter", "abuffersink"); | |
+ return -1; | |
+ } | |
+ | |
+ ret = av_opt_set_bin (c->sink, | |
+ "sample_fmts", | |
+ (uint8_t *) &c->output_sample_fmt, | |
+ sizeof (c->output_sample_fmt), | |
+ AV_OPT_SEARCH_CHILDREN); | |
+ if (ret < 0) | |
+ { | |
+ edc_rtsp_debug (rtsp, "%s", "failed to set output sample format"); | |
+ return -1; | |
+ } | |
+ | |
+ { | |
+ int64_t channel_layout; | |
+ | |
+ channel_layout = av_get_default_channel_layout (c->output_channels); | |
+ | |
+ ret = av_opt_set_bin (c->sink, | |
+ "channel_layouts", | |
+ (uint8_t *) &channel_layout, | |
+ sizeof (channel_layout), | |
+ AV_OPT_SEARCH_CHILDREN); | |
+ if (ret < 0) | |
+ { | |
+ edc_rtsp_debug (rtsp, "%s", "failed to set output channel layout"); | |
+ return -1; | |
+ } | |
+ } | |
+ | |
+ ret = av_opt_set_bin (c->sink, | |
+ "sample_rates", | |
+ (uint8_t *) &c->output_sample_rate, | |
+ sizeof (c->output_sample_rate), | |
+ AV_OPT_SEARCH_CHILDREN); | |
+ if (ret < 0) | |
+ { | |
+ edc_rtsp_debug (rtsp, "%s", "failed to set output sample rate"); | |
+ return -1; | |
+ } | |
+ | |
+ outputs = avfilter_inout_alloc (); | |
+ outputs->name = av_strdup ("in"); | |
+ outputs->filter_ctx = c->src; | |
+ outputs->pad_idx = 0; | |
+ outputs->next = NULL; | |
+ | |
+ inputs = avfilter_inout_alloc (); | |
+ inputs->name = av_strdup ("out"); | |
+ inputs->filter_ctx = c->sink; | |
+ inputs->pad_idx = 0; | |
+ inputs->next = NULL; | |
+ | |
+ do | |
+ { | |
+ ret = avfilter_graph_parse_ptr (c->graph, | |
+ "aresample", | |
+ &inputs, | |
+ &outputs, | |
+ NULL); | |
+ if (ret < 0) | |
+ { | |
+ edc_rtsp_debug (rtsp, "failed to parse audio filter graph : '%s'(%d)", | |
+ av_err2str (ret), ret); | |
+ avfilter_graph_free (&c->graph); | |
+ break; | |
+ } | |
+ | |
+ ret = avfilter_graph_config (c->graph, NULL); | |
+ if (ret < 0) | |
+ { | |
+ edc_rtsp_debug (rtsp, "failed to configure audio filter graph : '%s'(%d)", | |
+ av_err2str (ret), ret); | |
+ avfilter_graph_free (&c->graph); | |
+ break; | |
+ } | |
+ | |
+ //if (!(c->encoder->codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE)) | |
+ //av_buffersink_set_frame_size (c->sink, c->encoder->frame_size); | |
+ | |
+ if (1) | |
+ { | |
+ char *dump; | |
+ | |
+ dump = avfilter_graph_dump (c->graph, NULL); | |
+ if (dump) | |
+ { | |
+ edc_rtsp_debug (rtsp, "resampling filter graph\n%s", dump); | |
+ av_free (dump); | |
+ } | |
+ } | |
+ | |
+ ret = 0; | |
+ } | |
+ while (0); | |
+ | |
+ avfilter_inout_free (&inputs); | |
+ avfilter_inout_free (&outputs); | |
+ | |
+ return ret; | |
+} | |
+ | |
static void | |
edc_rtsp_handle_error (EdcRtsp *rtsp, | |
const char *fmt, | |
@@ -567,6 +746,9 @@ edc_rtsp_read_rtp_real (EdcRtsp *rtsp, | |
if (!pkt || pkt->size <= 0 || !pkt->data) | |
return NULL; | |
+ if (rtsp->base_timestamp == 0) | |
+ rtsp->base_timestamp = edc_get_real_time (); | |
+ | |
/* RTP extension header */ | |
if (rtsp->fmt.avfctx->rtp_ext_header_len > 0) | |
{ | |
@@ -584,19 +766,37 @@ edc_rtsp_read_rtp_real (EdcRtsp *rtsp, | |
buf = NULL; | |
if (pkt->stream_index == rtsp->fmt.video_stream) | |
{ | |
+ AVRational tb = { 1, 90000 }; | |
+ | |
+ if (rtsp->video.start_pts < 0) | |
+ rtsp->video.start_pts = pkt->pts; | |
+ | |
if (!rtsp->video.has_stream || | |
!rtsp->use_stream[EDC_RTSP_VIDEO]) | |
return NULL; | |
+ if (rtsp->video.start_pts > pkt->pts) | |
+ rtsp->video.start_pts = pkt->pts; | |
+ | |
+ pkt->pts -= rtsp->video.start_pts; | |
+ | |
+ if (0) edc_rtsp_log (rtsp, "video time:%s pts:%ld", av_ts2timestr (pkt->pts, &tb), pkt->pts); | |
+ | |
buf = rtsp->video.make_frame (rtsp, pkt); | |
if (buf) | |
{ | |
buf->width = rtsp->video.width; | |
buf->height = rtsp->video.height; | |
+ buf->timestamp = rtsp->base_timestamp + av_rescale_q (pkt->pts, tb, AV_TIME_BASE_Q); | |
} | |
} | |
else if (pkt->stream_index == rtsp->fmt.audio_stream) | |
{ | |
+ AVRational tb = { 1, 44100 }; | |
+ | |
+ if (rtsp->audio.start_pts < 0) | |
+ rtsp->audio.start_pts = pkt->pts; | |
+ | |
if (!rtsp->audio.has_stream || | |
!rtsp->use_stream[EDC_RTSP_AUDIO]) | |
return NULL; | |
@@ -604,7 +804,13 @@ edc_rtsp_read_rtp_real (EdcRtsp *rtsp, | |
if (rtsp->ignore_audio_frame) | |
return NULL; | |
+ pkt->pts -= rtsp->audio.start_pts; | |
+ | |
+ if (0) edc_rtsp_log (rtsp, "audio time:%s pts:%ld", av_ts2timestr (pkt->pts, &tb), pkt->pts); | |
+ | |
buf = rtsp->audio.make_frame (rtsp, pkt); | |
+ if (buf) | |
+ buf->timestamp = rtsp->base_timestamp + av_rescale_q (pkt->pts, tb, AV_TIME_BASE_Q); | |
} | |
else if (pkt->stream_index == rtsp->fmt.metadata_stream) | |
{ | |
@@ -973,6 +1179,144 @@ edc_rtsp_make_audio_frame_resampled (EdcRtsp *rtsp, | |
return buf; | |
} | |
+static EdcBuf * | |
+edc_rtsp_make_audio_frame_resampled2 (EdcRtsp *rtsp, | |
+ AVPacket *pkt) | |
+{ | |
+ EdcRtspConvert *c; | |
+ EdcBuf *buf = NULL; | |
+ int len, pcm_len; | |
+ const uint8_t **dec_data; | |
+ int dec_data_nb_samples; | |
+ int ret; | |
+ | |
+ c = &rtsp->audio.convert; | |
+ | |
+ dec_data = edc_codec_decode_audio2 (c->decoder, | |
+ (char *) pkt->data, | |
+ (int) pkt->size, | |
+ &dec_data_nb_samples); | |
+ if (!dec_data) | |
+ { | |
+ int error_count; | |
+ | |
+ error_count = edc_codec_get_error_count (c->decoder); | |
+ if (error_count <= 5 || (error_count % 100) == 0) | |
+ edc_rtsp_log (rtsp, | |
+ "failed to decode audio frame(%d) (count:%d)", | |
+ pkt->size, error_count); | |
+ | |
+ edc_rtsp_handle_error (rtsp, "Audio Resample"); | |
+ | |
+ return NULL; | |
+ } | |
+ | |
+ { | |
+ AVRational tb = (AVRational) { 1, c->output_sample_rate }; | |
+ AVFrame *frame; | |
+ | |
+ frame = av_frame_alloc (); | |
+ frame->pts = pkt->pts; | |
+ frame->pkt_dts = frame->pts; | |
+ frame->channel_layout = av_get_default_channel_layout (c->input_channels); | |
+ frame->channels = av_get_channel_layout_nb_channels (frame->channel_layout); | |
+ frame->sample_rate = c->input_sample_rate; | |
+ frame->format = c->input_sample_fmt; | |
+ frame->nb_samples = dec_data_nb_samples; | |
+ | |
+ avcodec_fill_audio_frame (frame, | |
+ frame->channels, | |
+ frame->format, | |
+ (const uint8_t *) dec_data[0], | |
+ 192000, | |
+ 0); | |
+ | |
+ if (0) edc_log ("audio decoded tb(%d/%d) nb_samples:%d sample_rate:%d fmt:%d layout:%ld time:%s pts:%s pkt_dts:%s", | |
+ tb.num, | |
+ tb.den, | |
+ frame->nb_samples, | |
+ frame->sample_rate, | |
+ frame->format, | |
+ frame->channel_layout, | |
+ av_ts2timestr (frame->pts, &tb), | |
+ av_ts2str (frame->pts), | |
+ av_ts2str (frame->pkt_dts)); | |
+ | |
+ /* send frame to the audio resampler */ | |
+ ret = av_buffersrc_add_frame_flags (c->src, | |
+ frame, | |
+ AV_BUFFERSRC_FLAG_KEEP_REF); | |
+ if (ret < 0) | |
+ edc_rtsp_debug (rtsp, "failed to add frame to buffersrc: '%s'(%d)", | |
+ av_err2str (ret), ret); | |
+ | |
+ av_frame_free (&frame); | |
+ } | |
+ | |
+ while (TRUE) | |
+ { | |
+ AVFrame *frame; | |
+ | |
+ frame = av_frame_alloc (); | |
+ | |
+ ret = av_buffersink_get_frame (c->sink, frame); | |
+ if (ret < 0) | |
+ { | |
+ if (ret != AVERROR (EAGAIN) && ret != AVERROR_EOF) | |
+ edc_rtsp_debug (rtsp, "failed to get frame from buffersink: '%s'(%d)", | |
+ av_err2str (ret), ret); | |
+ | |
+ av_frame_free (&frame); | |
+ break; | |
+ } | |
+ | |
+ if (0) | |
+ { | |
+ AVRational tb; | |
+ | |
+ tb = av_buffersink_get_time_base (c->sink); | |
+ edc_log ("audio resampled tb(%d/%d) nb_samples:%d sample_rate:%d fmt:%d layout:%ld time:%s pts:%s pkt_dts:%s", | |
+ tb.num, tb.den, | |
+ frame->nb_samples, | |
+ frame->sample_rate, | |
+ frame->format, | |
+ frame->channel_layout, | |
+ av_ts2timestr (frame->pts, &tb), | |
+ av_ts2str (frame->pts), | |
+ av_ts2str (frame->pkt_dts)); | |
+ } | |
+ | |
+ pcm_len = frame->nb_samples * c->output_bytes_per_sample * c->output_channels; | |
+ if (pcm_len <= 0) | |
+ { | |
+ av_frame_free (&frame); | |
+ break; | |
+ } | |
+ | |
+ /* ADCPM */ | |
+ buf = edc_buf_new ((pcm_len / 4) + 4 /* header */ + 4 /* dummy */); | |
+ len = edc_adpcm_encode (c->encoder, | |
+ (short *) frame->extended_data[0], | |
+ (unsigned char *) buf->data, | |
+ pcm_len); | |
+ if (len <= 0) | |
+ { | |
+ edc_buf_unref (buf); | |
+ return NULL; | |
+ } | |
+ | |
+ buf->channel = 0; | |
+ buf->flags = EDC_BUF_FLAG_AUDIO; | |
+ buf->codec_id = EDC_CODEC_ADPCM; | |
+ buf->len = len; | |
+ | |
+ av_frame_free (&frame); | |
+ break; | |
+ } | |
+ | |
+ return buf; | |
+} | |
+ | |
static EdcBuf * | |
edc_rtsp_make_audio_frame_encoded (EdcRtsp *rtsp, | |
AVPacket *pkt) | |
@@ -1526,7 +1870,13 @@ edc_rtsp_open_fmt (EdcRtsp *rtsp) | |
continue; | |
} | |
- rtsp->audio.make_frame = edc_rtsp_make_audio_frame_resampled; | |
+ if (0) | |
+ rtsp->audio.make_frame = edc_rtsp_make_audio_frame_resampled; | |
+ else | |
+ { | |
+ mp4serv_init_audio_resampling_filter (rtsp); | |
+ rtsp->audio.make_frame = edc_rtsp_make_audio_frame_resampled2; | |
+ } | |
} | |
else | |
{ | |
@@ -1891,6 +2241,9 @@ edc_rtsp_start (EdcRtsp *rtsp) | |
} | |
rtsp->started = TRUE; | |
rtsp->key_received = FALSE; | |
+ rtsp->base_timestamp = 0; | |
+ rtsp->video.start_pts = -1; | |
+ rtsp->audio.start_pts = -1; | |
edc_reset_rel_timestamp (&rtsp->rel_timestamp); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment