summaryrefslogtreecommitdiffstats
path: root/audio
diff options
context:
space:
mode:
Diffstat (limited to 'audio')
-rw-r--r--audio/decode/ad_spdif.c183
1 files changed, 76 insertions, 107 deletions
diff --git a/audio/decode/ad_spdif.c b/audio/decode/ad_spdif.c
index a53513dead..bb7cd27e93 100644
--- a/audio/decode/ad_spdif.c
+++ b/audio/decode/ad_spdif.c
@@ -30,138 +30,111 @@
#include "mpvcore/options.h"
#include "ad.h"
-#define FILENAME_SPDIFENC "spdif"
#define OUTBUF_SIZE 65536
+
struct spdifContext {
AVFormatContext *lavf_ctx;
int iec61937_packet_size;
int out_buffer_len;
int out_buffer_size;
uint8_t *out_buffer;
- uint8_t pb_buffer[OUTBUF_SIZE];
+ bool need_close;
};
-static void uninit(sh_audio_t *sh);
-
-static int read_packet(void *p, uint8_t *buf, int buf_size)
-{
- // spdifenc does not use read callback.
- return 0;
-}
-
static int write_packet(void *p, uint8_t *buf, int buf_size)
{
- int len;
struct spdifContext *ctx = p;
- len = FFMIN(buf_size, ctx->out_buffer_size -ctx->out_buffer_len);
- memcpy(&ctx->out_buffer[ctx->out_buffer_len], buf, len);
- ctx->out_buffer_len += len;
- return len;
+ int buffer_left = ctx->out_buffer_size - ctx->out_buffer_len;
+ if (buf_size > buffer_left) {
+ mp_msg(MSGT_DECAUDIO, MSGL_ERR, "spdif packet too large.\n");
+ buf_size = buffer_left;
+ }
+
+ memcpy(&ctx->out_buffer[ctx->out_buffer_len], buf, buf_size);
+ ctx->out_buffer_len += buf_size;
+ return buf_size;
}
-static int64_t seek(void *p, int64_t offset, int whence)
+static void uninit(sh_audio_t *sh)
{
- // spdifenc does not use seek callback.
- return 0;
+ struct spdifContext *spdif_ctx = sh->context;
+ AVFormatContext *lavf_ctx = spdif_ctx->lavf_ctx;
+
+ if (lavf_ctx) {
+ if (spdif_ctx->need_close)
+ av_write_trailer(lavf_ctx);
+ if (lavf_ctx->pb)
+ av_freep(&lavf_ctx->pb->buffer);
+ av_freep(&lavf_ctx->pb);
+ avformat_free_context(lavf_ctx);
+ }
+ talloc_free(spdif_ctx);
}
static int preinit(sh_audio_t *sh)
{
- sh->samplesize = 2;
return 1;
}
-static int codecs[] = {
- AV_CODEC_ID_AAC,
- AV_CODEC_ID_AC3,
- AV_CODEC_ID_DTS,
- AV_CODEC_ID_EAC3,
- AV_CODEC_ID_MP3,
- AV_CODEC_ID_TRUEHD,
- AV_CODEC_ID_NONE
-};
-
static int init(sh_audio_t *sh, const char *decoder)
{
- int srate, bps, *dtshd_rate;
- AVFormatContext *lavf_ctx = NULL;
- AVStream *stream = NULL;
- const AVOption *opt = NULL;
- struct spdifContext *spdif_ctx = NULL;
+ struct spdifContext *spdif_ctx = talloc_zero(NULL, struct spdifContext);
+ sh->context = spdif_ctx;
- spdif_ctx = av_mallocz(sizeof(*spdif_ctx));
- if (!spdif_ctx)
- goto fail;
- spdif_ctx->lavf_ctx = avformat_alloc_context();
- if (!spdif_ctx->lavf_ctx)
+ AVFormatContext *lavf_ctx = NULL;
+ if (avformat_alloc_output_context2(&lavf_ctx, NULL, "spdif", NULL) < 0)
goto fail;
- sh->context = spdif_ctx;
- lavf_ctx = spdif_ctx->lavf_ctx;
+ spdif_ctx->lavf_ctx = lavf_ctx;
- lavf_ctx->oformat = av_guess_format(FILENAME_SPDIFENC, NULL, NULL);
- if (!lavf_ctx->oformat)
- goto fail;
- lavf_ctx->priv_data = av_mallocz(lavf_ctx->oformat->priv_data_size);
- if (!lavf_ctx->priv_data)
- goto fail;
- lavf_ctx->pb = avio_alloc_context(spdif_ctx->pb_buffer, OUTBUF_SIZE, 1, spdif_ctx,
- read_packet, write_packet, seek);
- if (!lavf_ctx->pb)
+ void *buffer = av_mallocz(OUTBUF_SIZE);
+ if (!buffer)
+ abort();
+ lavf_ctx->pb = avio_alloc_context(buffer, OUTBUF_SIZE, 1, spdif_ctx, NULL,
+ write_packet, NULL);
+ if (!lavf_ctx->pb) {
+ av_free(buffer);
goto fail;
- stream = avformat_new_stream(lavf_ctx, 0);
+ }
+
+ // Request minimal buffering
+ lavf_ctx->pb->direct = 1;
+
+ AVStream *stream = avformat_new_stream(lavf_ctx, 0);
if (!stream)
goto fail;
- lavf_ctx->duration = AV_NOPTS_VALUE;
- lavf_ctx->start_time = AV_NOPTS_VALUE;
- lavf_ctx->streams[0]->codec->codec_id = mp_codec_to_av_codec_id(decoder);
- lavf_ctx->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE;
- if (AVERROR_PATCHWELCOME == lavf_ctx->oformat->write_header(lavf_ctx)) {
- mp_msg(MSGT_DECAUDIO,MSGL_INFO,
- "This codec is not supported by spdifenc.\n");
- goto fail;
- }
- srate = 48000; //fake value
- bps = 768000/8; //fake value
+ stream->codec->codec_id = mp_codec_to_av_codec_id(decoder);
+
+ AVDictionary *format_opts = NULL;
int num_channels = 0;
- switch (lavf_ctx->streams[0]->codec->codec_id) {
+ switch (stream->codec->codec_id) {
case AV_CODEC_ID_AAC:
spdif_ctx->iec61937_packet_size = 16384;
sh->sample_format = AF_FORMAT_IEC61937_LE;
- sh->samplerate = srate;
+ sh->samplerate = 48000;
num_channels = 2;
- sh->i_bps = bps;
break;
case AV_CODEC_ID_AC3:
spdif_ctx->iec61937_packet_size = 6144;
sh->sample_format = AF_FORMAT_AC3_LE;
- sh->samplerate = srate;
+ sh->samplerate = 48000;
num_channels = 2;
- sh->i_bps = bps;
break;
case AV_CODEC_ID_DTS:
- if(sh->opts->dtshd) {
- opt = av_opt_find(&lavf_ctx->oformat->priv_class,
- "dtshd_rate", NULL, 0, 0);
- if (!opt)
- goto fail;
- dtshd_rate = (int*)(((uint8_t*)lavf_ctx->priv_data) +
- opt->offset);
- *dtshd_rate = 192000*4;
+ if (sh->opts->dtshd) {
+ av_dict_set(&format_opts, "dtshd_rate", "768000", 0); // 4*192000
spdif_ctx->iec61937_packet_size = 32768;
sh->sample_format = AF_FORMAT_IEC61937_LE;
sh->samplerate = 192000; // DTS core require 48000
num_channels = 2*4;
- sh->i_bps = bps;
} else {
spdif_ctx->iec61937_packet_size = 32768;
sh->sample_format = AF_FORMAT_AC3_LE;
- sh->samplerate = srate;
+ sh->samplerate = 48000;
num_channels = 2;
- sh->i_bps = bps;
}
break;
case AV_CODEC_ID_EAC3:
@@ -169,28 +142,35 @@ static int init(sh_audio_t *sh, const char *decoder)
sh->sample_format = AF_FORMAT_IEC61937_LE;
sh->samplerate = 192000;
num_channels = 2;
- sh->i_bps = bps;
break;
case AV_CODEC_ID_MP3:
spdif_ctx->iec61937_packet_size = 4608;
sh->sample_format = AF_FORMAT_MPEG2;
- sh->samplerate = srate;
+ sh->samplerate = 48000;
num_channels = 2;
- sh->i_bps = bps;
break;
case AV_CODEC_ID_TRUEHD:
spdif_ctx->iec61937_packet_size = 61440;
sh->sample_format = AF_FORMAT_IEC61937_LE;
sh->samplerate = 192000;
num_channels = 8;
- sh->i_bps = bps;
break;
default:
- break;
+ abort();
}
if (num_channels)
mp_chmap_from_channels(&sh->channels, num_channels);
+ if (avformat_write_header(lavf_ctx, &format_opts) < 0) {
+ mp_msg(MSGT_DECAUDIO, MSGL_FATAL,
+ "libavformat spdif initialization failed.\n");
+ av_dict_free(&format_opts);
+ goto fail;
+ }
+ av_dict_free(&format_opts);
+
+ spdif_ctx->need_close = true;
+
return 1;
fail:
@@ -203,7 +183,6 @@ static int decode_audio(sh_audio_t *sh, unsigned char *buf,
{
struct spdifContext *spdif_ctx = sh->context;
AVFormatContext *lavf_ctx = spdif_ctx->lavf_ctx;
- AVPacket pkt;
spdif_ctx->out_buffer_len = 0;
spdif_ctx->out_buffer_size = maxlen;
@@ -213,15 +192,16 @@ static int decode_audio(sh_audio_t *sh, unsigned char *buf,
struct demux_packet *mpkt = demux_read_packet(sh->gsh);
if (!mpkt)
break;
+ AVPacket pkt;
mp_set_av_packet(&pkt, mpkt);
- mp_msg(MSGT_DECAUDIO,MSGL_V, "pkt.data[%p] pkt.size[%d]\n",
- pkt.data, pkt.size);
+ pkt.pts = pkt.dts = 0;
+ mp_msg(MSGT_DECAUDIO, MSGL_V, "spdif packet, size=%d\n", pkt.size);
if (mpkt->pts != MP_NOPTS_VALUE) {
sh->pts = mpkt->pts;
sh->pts_bytes = 0;
}
int out_len = spdif_ctx->out_buffer_len;
- int ret = lavf_ctx->oformat->write_packet(lavf_ctx, &pkt);
+ int ret = av_write_frame(lavf_ctx, &pkt);
avio_flush(lavf_ctx->pb);
sh->pts_bytes += spdif_ctx->out_buffer_len - out_len;
talloc_free(mpkt);
@@ -236,26 +216,15 @@ static int control(sh_audio_t *sh, int cmd, void *arg)
return CONTROL_UNKNOWN;
}
-static void uninit(sh_audio_t *sh)
-{
- struct spdifContext *spdif_ctx = sh->context;
- AVFormatContext *lavf_ctx = spdif_ctx->lavf_ctx;
-
- if (lavf_ctx) {
- if (lavf_ctx->oformat)
- lavf_ctx->oformat->write_trailer(lavf_ctx);
- av_freep(&lavf_ctx->pb);
- if (lavf_ctx->streams) {
- av_freep(&lavf_ctx->streams[0]->codec);
- av_freep(&lavf_ctx->streams[0]->info);
- av_freep(&lavf_ctx->streams[0]);
- }
- av_freep(&lavf_ctx->streams);
- av_freep(&lavf_ctx->priv_data);
- }
- av_freep(&lavf_ctx);
- av_freep(&spdif_ctx);
-}
+static const int codecs[] = {
+ AV_CODEC_ID_AAC,
+ AV_CODEC_ID_AC3,
+ AV_CODEC_ID_DTS,
+ AV_CODEC_ID_EAC3,
+ AV_CODEC_ID_MP3,
+ AV_CODEC_ID_TRUEHD,
+ AV_CODEC_ID_NONE
+};
static void add_decoders(struct mp_decoder_list *list)
{