Created
August 24, 2018 06:54
-
-
Save moonpfe/9f433d76aba055bfe3dd49629191943a to your computer and use it in GitHub Desktop.
카메라에서 수신한 PCMA 오디오 패킷을 FFmpeg ADPCM 인코더로 재인코딩하고 디코딩하기
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/src/mp4serv.c b/src/mp4serv.c | |
index 4b84abc30..f73d7704b 100644 | |
--- a/src/mp4serv.c | |
+++ b/src/mp4serv.c | |
@@ -123,21 +123,18 @@ struct _Mp4ServClient | |
struct | |
{ | |
- EdcAdpcm *decoder; | |
+ AVCodecContext *decoder; | |
AVFilterGraph *graph; | |
AVFilterContext *src; | |
AVFilterContext *sink; | |
AVCodecContext *encoder; | |
AVStream *stream; | |
- char *buf; | |
- int buf_len; | |
- int buf_alloc; | |
- | |
int input_sample_fmt; | |
int input_channel_layout; | |
AVRational input_time_base; | |
int sample_rate; | |
+ int output_sample_rate; | |
int64_t rescale_delta_last; | |
} audio; | |
@@ -558,12 +555,18 @@ mp4serv_init_audio (Mp4ServClient *client, | |
return; | |
} | |
- client->audio.decoder = edc_adpcm_new (); | |
- client->audio.buf_alloc = 1920 * 2; | |
- client->audio.buf = g_malloc (client->audio.buf_alloc + AV_INPUT_BUFFER_PADDING_SIZE); | |
- client->audio.buf_len = 0; | |
- client->audio.input_sample_fmt = in_par->format; | |
- client->audio.input_channel_layout = in_par->channel_layout; | |
+ client->audio.decoder = avcodec_alloc_context3 (decoder); | |
+ avcodec_parameters_to_context (client->audio.decoder, in_par); | |
+ | |
+ ret = avcodec_open2 (client->audio.decoder, decoder, NULL); | |
+ if (ret < 0) | |
+ { | |
+ mp4serv_debug (client, "failed to open audio decoder: '%s'(%d)", | |
+ av_err2str (ret), ret); | |
+ return; | |
+ } | |
+ | |
+ avcodec_parameters_from_context (in_par, client->audio.decoder); | |
ret = mp4serv_init_audio_resampling_filter (client, in_par); | |
if (ret < 0) | |
@@ -579,16 +582,11 @@ mp4serv_deinit_audio (Mp4ServClient *client) | |
{ | |
if (client->audio.decoder) | |
{ | |
- edc_adpcm_unref (client->audio.decoder); | |
+ avcodec_free_context (&client->audio.decoder); | |
client->audio.decoder = NULL; | |
} | |
if (client->audio.graph) | |
avfilter_graph_free (&client->audio.graph); | |
- | |
- g_free (client->audio.buf); | |
- client->audio.buf = NULL; | |
- client->audio.buf_alloc = 0; | |
- client->audio.buf_len = 0; | |
} | |
static void | |
@@ -668,6 +666,119 @@ mp4serv_close_transcoder (Mp4ServClient *client, | |
client->ofmt = NULL; | |
} | |
+static uint8_t * | |
+mp4serv_get_extradata (EdcBuf *frame, | |
+ int *extradata_size) | |
+{ | |
+ AVBSFContext *bsf; | |
+ const AVBitStreamFilter *f; | |
+ const enum AVCodecID *ids; | |
+ AVPacket *dst_pkt; | |
+ int avcodec_id; | |
+ int found; | |
+ int ret; | |
+ AVPacket pkt; | |
+ AVPacket *pkt_ref; | |
+ uint8_t *data; | |
+ | |
+ data = NULL; | |
+ if (extradata_size) | |
+ *extradata_size = 0; | |
+ | |
+ f = av_bsf_get_by_name ("extract_extradata"); | |
+ if (!f || !f->codec_ids) | |
+ return data; | |
+ | |
+ avcodec_id = edc_codec_lookup_avcodec_id (frame->codec_id); | |
+ | |
+ found = 0; | |
+ for (ids = f->codec_ids; *ids != AV_CODEC_ID_NONE; ids++) | |
+ { | |
+ if (*ids == avcodec_id) | |
+ { | |
+ found = 1; | |
+ break; | |
+ } | |
+ } | |
+ | |
+ if (!found) | |
+ return data; | |
+ | |
+ bsf = NULL; | |
+ ret = av_bsf_alloc (f, &bsf); | |
+ if (ret < 0) | |
+ return data; | |
+ | |
+ bsf->par_in->codec_id = avcodec_id; | |
+ ret = av_bsf_init (bsf); | |
+ if (ret < 0) | |
+ { | |
+ av_bsf_free (&bsf); | |
+ | |
+ return data; | |
+ } | |
+ | |
+ dst_pkt = av_packet_alloc (); | |
+ pkt_ref = dst_pkt; | |
+ | |
+ av_init_packet (&pkt); | |
+ pkt.data = (uint8_t *) frame->data; | |
+ pkt.size = frame->len; | |
+ if (frame->flags & EDC_BUF_FLAG_KEY_FRAME) | |
+ pkt.flags |= AV_PKT_FLAG_KEY; | |
+ | |
+ ret = av_packet_ref (pkt_ref, &pkt); | |
+ if (ret < 0) | |
+ goto end_of_extract_extradata; | |
+ | |
+ ret = av_bsf_send_packet (bsf, pkt_ref); | |
+ if (ret < 0) | |
+ { | |
+ av_packet_unref (pkt_ref); | |
+ | |
+ goto end_of_extract_extradata; | |
+ } | |
+ | |
+ ret = 0; | |
+ while (ret >= 0) | |
+ { | |
+ uint8_t *extra; | |
+ int extra_size; | |
+ | |
+ ret = av_bsf_receive_packet (bsf, pkt_ref); | |
+ if (ret < 0) | |
+ { | |
+ if (ret != AVERROR (EAGAIN) && ret != AVERROR_EOF) | |
+ break; | |
+ | |
+ continue; | |
+ } | |
+ | |
+ extra = av_packet_get_side_data (pkt_ref, | |
+ AV_PKT_DATA_NEW_EXTRADATA, | |
+ &extra_size); | |
+ if (extra && extra_size > 0) | |
+ { | |
+ data = g_malloc0 (extra_size + AV_INPUT_BUFFER_PADDING_SIZE); | |
+ memcpy (data, extra, extra_size); | |
+ if (extradata_size) | |
+ *extradata_size = extra_size; | |
+ | |
+ av_packet_unref (pkt_ref); | |
+ break; | |
+ } | |
+ | |
+ av_packet_unref (pkt_ref); | |
+ } | |
+ | |
+end_of_extract_extradata: | |
+ | |
+ av_bsf_free (&bsf); | |
+ av_packet_free (&dst_pkt); | |
+ | |
+ return data; | |
+} | |
+ | |
static void | |
mp4serv_init_extradata (Mp4ServClient *client, | |
AVStream *stream) | |
@@ -873,6 +984,14 @@ mp4serv_open_transcoder (Mp4ServClient *client, | |
st->codecpar->format = AV_PIX_FMT_YUV420P; | |
st->codecpar->width = video_width; | |
st->codecpar->height = video_height; | |
+ if (client->video.extradata.data && client->video.extradata.size > 0) | |
+ { | |
+ st->codecpar->extradata_size = client->video.extradata.size; | |
+ st->codecpar->extradata = av_mallocz (client->video.extradata.size + AV_INPUT_BUFFER_PADDING_SIZE); | |
+ memcpy (st->codecpar->extradata, | |
+ client->video.extradata.data, | |
+ client->video.extradata.size); | |
+ } | |
ret = avcodec_parameters_to_context (client->video.codec, st->codecpar); | |
if (ret < 0) | |
@@ -919,8 +1038,8 @@ mp4serv_open_transcoder (Mp4ServClient *client, | |
stream->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; | |
stream->codecpar->codec_id = avcodec_id; | |
stream->codecpar->format = AV_SAMPLE_FMT_FLTP; | |
- stream->codecpar->sample_rate = client->audio.sample_rate; | |
- stream->codecpar->channel_layout = AV_CH_LAYOUT_STEREO; | |
+ stream->codecpar->sample_rate = client->audio.output_sample_rate; | |
+ stream->codecpar->channel_layout = AV_CH_LAYOUT_MONO; | |
stream->codecpar->channels = | |
av_get_channel_layout_nb_channels (stream->codecpar->channel_layout); | |
@@ -1345,49 +1464,38 @@ mp4serv_transcode (Mp4ServClient *client, | |
av_ts2str (packet->duration), | |
av_ts2str (packet->pos), | |
packet->size); | |
- do | |
+ | |
+ packet->dts = av_rescale_q (packet->dts, | |
+ client->audio.input_time_base, | |
+ client->audio.decoder->time_base); | |
+ packet->pts = packet->dts; | |
+ | |
+ ret = avcodec_send_packet (client->audio.decoder, packet); | |
+ if (ret < 0 && ret != AVERROR (EAGAIN) && ret != AVERROR_EOF) | |
+ mp4serv_debug (client, "failed to send audio packet to decoder: '%s'(%d)", | |
+ av_err2str (ret), ret); | |
+ | |
+ while (TRUE) | |
{ | |
- AVFrame *frame; | |
- int pcm_len; | |
- int dec_size; | |
AVRational time_base = { 1, client->audio.sample_rate }; | |
+ AVFrame *frame; | |
- dec_size = (packet->size - 4) * 4; | |
- if (dec_size > client->audio.buf_alloc) | |
- { | |
- client->audio.buf_alloc = dec_size + AV_INPUT_BUFFER_PADDING_SIZE; | |
- client->audio.buf = g_realloc (client->audio.buf, | |
- client->audio.buf_alloc); | |
- } | |
+ frame = av_frame_alloc (); | |
- pcm_len = edc_adpcm_decode (client->audio.decoder, | |
- (const uint8_t *) packet->data, | |
- (int16_t *) client->audio.buf, | |
- packet->size); | |
- if (pcm_len <= 0) | |
- break; | |
+ ret = avcodec_receive_frame (client->audio.decoder, frame); | |
+ if (ret < 0) | |
+ { | |
+ if (0 && ret != AVERROR (EAGAIN) && ret != AVERROR_EOF) | |
+ mp4serv_debug (client, "failed to get decoded audio frame: '%s'(%d)", | |
+ av_err2str (ret), ret); | |
- frame = av_frame_alloc (); | |
- frame->pts = packet->pts; | |
- frame->pkt_dts = frame->pts; | |
- frame->channel_layout = client->audio.input_channel_layout; | |
- frame->channels = av_get_channel_layout_nb_channels (frame->channel_layout); | |
- frame->sample_rate = client->audio.sample_rate; | |
- frame->format = client->audio.input_sample_fmt; | |
- frame->nb_samples = pcm_len | |
- / av_get_bytes_per_sample (frame->format) | |
- / frame->channels; | |
- | |
- avcodec_fill_audio_frame (frame, | |
- frame->channels, | |
- frame->format, | |
- (const uint8_t *) client->audio.buf, | |
- client->audio.buf_alloc, | |
- 0); | |
+ av_frame_free (&frame); | |
+ break; | |
+ } | |
- frame->pts = av_rescale_delta (client->audio.input_time_base, | |
+ frame->pts = av_rescale_delta (client->audio.decoder->time_base, | |
frame->pts, | |
- time_base, | |
+ (AVRational) {1, client->audio.decoder->sample_rate }, | |
frame->nb_samples, | |
&client->audio.rescale_delta_last, | |
time_base); | |
@@ -1413,7 +1521,6 @@ mp4serv_transcode (Mp4ServClient *client, | |
av_frame_free (&frame); | |
} | |
- while (0); | |
while (TRUE) | |
{ | |
@@ -2098,12 +2205,15 @@ mp4serv_feed_frame (Mp4ServStream *stream, | |
in_par->channel_layout = AV_CH_LAYOUT_MONO; | |
in_par->channels = | |
av_get_channel_layout_nb_channels (in_par->channel_layout); | |
- in_par->sample_rate = 8000; | |
in_par->block_align = 1024; | |
} | |
else | |
in_par = NULL; | |
+ if (!client->video.extradata.data) | |
+ client->video.extradata.data = | |
+ mp4serv_get_extradata (frame, &client->video.extradata.size); | |
+ | |
ret = mp4serv_open_transcoder (client, | |
frame->codec_id, | |
frame->width, | |
@@ -2435,8 +2545,9 @@ mp4serv_new_client (Mp4ServClientType type, | |
break; | |
} | |
- client->use_audio = FALSE; | |
+ client->use_audio = TRUE; | |
client->audio.sample_rate = 8000; | |
+ client->audio.output_sample_rate = 8000; | |
return client; | |
} |
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-codec.c b/edc-codec.c | |
index b9cae9bb..8b17485e 100644 | |
--- a/edc-codec.c | |
+++ b/edc-codec.c | |
@@ -579,7 +579,7 @@ edc_codec_new (EdcCodecID codec_id, | |
else | |
codec->context_name = edc_strdup (codec->is_video ? "video" : "audio"); | |
- if (codec_id == EDC_CODEC_ADPCM) | |
+ if (0 && codec_id == EDC_CODEC_ADPCM) | |
{ | |
codec->adpcm = edc_adpcm_new (); | |
if (!codec->adpcm) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment