mirror of
https://github.com/mpv-player/mpv
synced 2025-04-07 01:53:06 +00:00
ad_spdif: fix libavformat API usage
This accessed tons of private libavformat symbols all over the place. Don't do this and convert all code to proper public APIs. As a consequence, the code becomes shorter and cleaner (many things the code tried are done by libavformat APIs).
This commit is contained in:
parent
370c5cc834
commit
ebc4ccbbfa
@ -30,138 +30,111 @@
|
|||||||
#include "mpvcore/options.h"
|
#include "mpvcore/options.h"
|
||||||
#include "ad.h"
|
#include "ad.h"
|
||||||
|
|
||||||
#define FILENAME_SPDIFENC "spdif"
|
|
||||||
#define OUTBUF_SIZE 65536
|
#define OUTBUF_SIZE 65536
|
||||||
|
|
||||||
struct spdifContext {
|
struct spdifContext {
|
||||||
AVFormatContext *lavf_ctx;
|
AVFormatContext *lavf_ctx;
|
||||||
int iec61937_packet_size;
|
int iec61937_packet_size;
|
||||||
int out_buffer_len;
|
int out_buffer_len;
|
||||||
int out_buffer_size;
|
int out_buffer_size;
|
||||||
uint8_t *out_buffer;
|
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)
|
static int write_packet(void *p, uint8_t *buf, int buf_size)
|
||||||
{
|
{
|
||||||
int len;
|
|
||||||
struct spdifContext *ctx = p;
|
struct spdifContext *ctx = p;
|
||||||
|
|
||||||
len = FFMIN(buf_size, ctx->out_buffer_size -ctx->out_buffer_len);
|
int buffer_left = ctx->out_buffer_size - ctx->out_buffer_len;
|
||||||
memcpy(&ctx->out_buffer[ctx->out_buffer_len], buf, len);
|
if (buf_size > buffer_left) {
|
||||||
ctx->out_buffer_len += len;
|
mp_msg(MSGT_DECAUDIO, MSGL_ERR, "spdif packet too large.\n");
|
||||||
return len;
|
buf_size = buffer_left;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t seek(void *p, int64_t offset, int whence)
|
memcpy(&ctx->out_buffer[ctx->out_buffer_len], buf, buf_size);
|
||||||
|
ctx->out_buffer_len += buf_size;
|
||||||
|
return buf_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void uninit(sh_audio_t *sh)
|
||||||
{
|
{
|
||||||
// spdifenc does not use seek callback.
|
struct spdifContext *spdif_ctx = sh->context;
|
||||||
return 0;
|
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)
|
static int preinit(sh_audio_t *sh)
|
||||||
{
|
{
|
||||||
sh->samplesize = 2;
|
|
||||||
return 1;
|
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)
|
static int init(sh_audio_t *sh, const char *decoder)
|
||||||
{
|
{
|
||||||
int srate, bps, *dtshd_rate;
|
struct spdifContext *spdif_ctx = talloc_zero(NULL, struct spdifContext);
|
||||||
AVFormatContext *lavf_ctx = NULL;
|
|
||||||
AVStream *stream = NULL;
|
|
||||||
const AVOption *opt = NULL;
|
|
||||||
struct spdifContext *spdif_ctx = NULL;
|
|
||||||
|
|
||||||
spdif_ctx = av_mallocz(sizeof(*spdif_ctx));
|
|
||||||
if (!spdif_ctx)
|
|
||||||
goto fail;
|
|
||||||
spdif_ctx->lavf_ctx = avformat_alloc_context();
|
|
||||||
if (!spdif_ctx->lavf_ctx)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
sh->context = spdif_ctx;
|
sh->context = spdif_ctx;
|
||||||
lavf_ctx = spdif_ctx->lavf_ctx;
|
|
||||||
|
|
||||||
lavf_ctx->oformat = av_guess_format(FILENAME_SPDIFENC, NULL, NULL);
|
AVFormatContext *lavf_ctx = NULL;
|
||||||
if (!lavf_ctx->oformat)
|
if (avformat_alloc_output_context2(&lavf_ctx, NULL, "spdif", NULL) < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
lavf_ctx->priv_data = av_mallocz(lavf_ctx->oformat->priv_data_size);
|
|
||||||
if (!lavf_ctx->priv_data)
|
spdif_ctx->lavf_ctx = lavf_ctx;
|
||||||
goto fail;
|
|
||||||
lavf_ctx->pb = avio_alloc_context(spdif_ctx->pb_buffer, OUTBUF_SIZE, 1, spdif_ctx,
|
void *buffer = av_mallocz(OUTBUF_SIZE);
|
||||||
read_packet, write_packet, seek);
|
if (!buffer)
|
||||||
if (!lavf_ctx->pb)
|
abort();
|
||||||
goto fail;
|
lavf_ctx->pb = avio_alloc_context(buffer, OUTBUF_SIZE, 1, spdif_ctx, NULL,
|
||||||
stream = avformat_new_stream(lavf_ctx, 0);
|
write_packet, NULL);
|
||||||
if (!stream)
|
if (!lavf_ctx->pb) {
|
||||||
goto fail;
|
av_free(buffer);
|
||||||
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;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
srate = 48000; //fake value
|
// Request minimal buffering
|
||||||
bps = 768000/8; //fake value
|
lavf_ctx->pb->direct = 1;
|
||||||
|
|
||||||
|
AVStream *stream = avformat_new_stream(lavf_ctx, 0);
|
||||||
|
if (!stream)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
stream->codec->codec_id = mp_codec_to_av_codec_id(decoder);
|
||||||
|
|
||||||
|
AVDictionary *format_opts = NULL;
|
||||||
|
|
||||||
int num_channels = 0;
|
int num_channels = 0;
|
||||||
switch (lavf_ctx->streams[0]->codec->codec_id) {
|
switch (stream->codec->codec_id) {
|
||||||
case AV_CODEC_ID_AAC:
|
case AV_CODEC_ID_AAC:
|
||||||
spdif_ctx->iec61937_packet_size = 16384;
|
spdif_ctx->iec61937_packet_size = 16384;
|
||||||
sh->sample_format = AF_FORMAT_IEC61937_LE;
|
sh->sample_format = AF_FORMAT_IEC61937_LE;
|
||||||
sh->samplerate = srate;
|
sh->samplerate = 48000;
|
||||||
num_channels = 2;
|
num_channels = 2;
|
||||||
sh->i_bps = bps;
|
|
||||||
break;
|
break;
|
||||||
case AV_CODEC_ID_AC3:
|
case AV_CODEC_ID_AC3:
|
||||||
spdif_ctx->iec61937_packet_size = 6144;
|
spdif_ctx->iec61937_packet_size = 6144;
|
||||||
sh->sample_format = AF_FORMAT_AC3_LE;
|
sh->sample_format = AF_FORMAT_AC3_LE;
|
||||||
sh->samplerate = srate;
|
sh->samplerate = 48000;
|
||||||
num_channels = 2;
|
num_channels = 2;
|
||||||
sh->i_bps = bps;
|
|
||||||
break;
|
break;
|
||||||
case AV_CODEC_ID_DTS:
|
case AV_CODEC_ID_DTS:
|
||||||
if (sh->opts->dtshd) {
|
if (sh->opts->dtshd) {
|
||||||
opt = av_opt_find(&lavf_ctx->oformat->priv_class,
|
av_dict_set(&format_opts, "dtshd_rate", "768000", 0); // 4*192000
|
||||||
"dtshd_rate", NULL, 0, 0);
|
|
||||||
if (!opt)
|
|
||||||
goto fail;
|
|
||||||
dtshd_rate = (int*)(((uint8_t*)lavf_ctx->priv_data) +
|
|
||||||
opt->offset);
|
|
||||||
*dtshd_rate = 192000*4;
|
|
||||||
spdif_ctx->iec61937_packet_size = 32768;
|
spdif_ctx->iec61937_packet_size = 32768;
|
||||||
sh->sample_format = AF_FORMAT_IEC61937_LE;
|
sh->sample_format = AF_FORMAT_IEC61937_LE;
|
||||||
sh->samplerate = 192000; // DTS core require 48000
|
sh->samplerate = 192000; // DTS core require 48000
|
||||||
num_channels = 2*4;
|
num_channels = 2*4;
|
||||||
sh->i_bps = bps;
|
|
||||||
} else {
|
} else {
|
||||||
spdif_ctx->iec61937_packet_size = 32768;
|
spdif_ctx->iec61937_packet_size = 32768;
|
||||||
sh->sample_format = AF_FORMAT_AC3_LE;
|
sh->sample_format = AF_FORMAT_AC3_LE;
|
||||||
sh->samplerate = srate;
|
sh->samplerate = 48000;
|
||||||
num_channels = 2;
|
num_channels = 2;
|
||||||
sh->i_bps = bps;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AV_CODEC_ID_EAC3:
|
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->sample_format = AF_FORMAT_IEC61937_LE;
|
||||||
sh->samplerate = 192000;
|
sh->samplerate = 192000;
|
||||||
num_channels = 2;
|
num_channels = 2;
|
||||||
sh->i_bps = bps;
|
|
||||||
break;
|
break;
|
||||||
case AV_CODEC_ID_MP3:
|
case AV_CODEC_ID_MP3:
|
||||||
spdif_ctx->iec61937_packet_size = 4608;
|
spdif_ctx->iec61937_packet_size = 4608;
|
||||||
sh->sample_format = AF_FORMAT_MPEG2;
|
sh->sample_format = AF_FORMAT_MPEG2;
|
||||||
sh->samplerate = srate;
|
sh->samplerate = 48000;
|
||||||
num_channels = 2;
|
num_channels = 2;
|
||||||
sh->i_bps = bps;
|
|
||||||
break;
|
break;
|
||||||
case AV_CODEC_ID_TRUEHD:
|
case AV_CODEC_ID_TRUEHD:
|
||||||
spdif_ctx->iec61937_packet_size = 61440;
|
spdif_ctx->iec61937_packet_size = 61440;
|
||||||
sh->sample_format = AF_FORMAT_IEC61937_LE;
|
sh->sample_format = AF_FORMAT_IEC61937_LE;
|
||||||
sh->samplerate = 192000;
|
sh->samplerate = 192000;
|
||||||
num_channels = 8;
|
num_channels = 8;
|
||||||
sh->i_bps = bps;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
abort();
|
||||||
}
|
}
|
||||||
if (num_channels)
|
if (num_channels)
|
||||||
mp_chmap_from_channels(&sh->channels, 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;
|
return 1;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
@ -203,7 +183,6 @@ static int decode_audio(sh_audio_t *sh, unsigned char *buf,
|
|||||||
{
|
{
|
||||||
struct spdifContext *spdif_ctx = sh->context;
|
struct spdifContext *spdif_ctx = sh->context;
|
||||||
AVFormatContext *lavf_ctx = spdif_ctx->lavf_ctx;
|
AVFormatContext *lavf_ctx = spdif_ctx->lavf_ctx;
|
||||||
AVPacket pkt;
|
|
||||||
|
|
||||||
spdif_ctx->out_buffer_len = 0;
|
spdif_ctx->out_buffer_len = 0;
|
||||||
spdif_ctx->out_buffer_size = maxlen;
|
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);
|
struct demux_packet *mpkt = demux_read_packet(sh->gsh);
|
||||||
if (!mpkt)
|
if (!mpkt)
|
||||||
break;
|
break;
|
||||||
|
AVPacket pkt;
|
||||||
mp_set_av_packet(&pkt, mpkt);
|
mp_set_av_packet(&pkt, mpkt);
|
||||||
mp_msg(MSGT_DECAUDIO,MSGL_V, "pkt.data[%p] pkt.size[%d]\n",
|
pkt.pts = pkt.dts = 0;
|
||||||
pkt.data, pkt.size);
|
mp_msg(MSGT_DECAUDIO, MSGL_V, "spdif packet, size=%d\n", pkt.size);
|
||||||
if (mpkt->pts != MP_NOPTS_VALUE) {
|
if (mpkt->pts != MP_NOPTS_VALUE) {
|
||||||
sh->pts = mpkt->pts;
|
sh->pts = mpkt->pts;
|
||||||
sh->pts_bytes = 0;
|
sh->pts_bytes = 0;
|
||||||
}
|
}
|
||||||
int out_len = spdif_ctx->out_buffer_len;
|
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);
|
avio_flush(lavf_ctx->pb);
|
||||||
sh->pts_bytes += spdif_ctx->out_buffer_len - out_len;
|
sh->pts_bytes += spdif_ctx->out_buffer_len - out_len;
|
||||||
talloc_free(mpkt);
|
talloc_free(mpkt);
|
||||||
@ -236,26 +216,15 @@ static int control(sh_audio_t *sh, int cmd, void *arg)
|
|||||||
return CONTROL_UNKNOWN;
|
return CONTROL_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void uninit(sh_audio_t *sh)
|
static const int codecs[] = {
|
||||||
{
|
AV_CODEC_ID_AAC,
|
||||||
struct spdifContext *spdif_ctx = sh->context;
|
AV_CODEC_ID_AC3,
|
||||||
AVFormatContext *lavf_ctx = spdif_ctx->lavf_ctx;
|
AV_CODEC_ID_DTS,
|
||||||
|
AV_CODEC_ID_EAC3,
|
||||||
if (lavf_ctx) {
|
AV_CODEC_ID_MP3,
|
||||||
if (lavf_ctx->oformat)
|
AV_CODEC_ID_TRUEHD,
|
||||||
lavf_ctx->oformat->write_trailer(lavf_ctx);
|
AV_CODEC_ID_NONE
|
||||||
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 void add_decoders(struct mp_decoder_list *list)
|
static void add_decoders(struct mp_decoder_list *list)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user