Skip to content

Instantly share code, notes, and snippets.

@moonpfe
Created August 24, 2018 06:54
Show Gist options
  • Save moonpfe/9f433d76aba055bfe3dd49629191943a to your computer and use it in GitHub Desktop.
Save moonpfe/9f433d76aba055bfe3dd49629191943a to your computer and use it in GitHub Desktop.
카메라에서 수신한 PCMA 오디오 패킷을 FFmpeg ADPCM 인코더로 재인코딩하고 디코딩하기
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;
}
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