Browse Source

MT#55283 split out media_player_coder

All structures related to en/decoding can go into a separate struct so
that they can be reused.

Change-Id: I74ba2e4a54cd8d4b2828b0923f70e5ebbe32e653
pull/1592/head
Richard Fuchs 3 years ago
parent
commit
a3b30f0e78
5 changed files with 90 additions and 84 deletions
  1. +2
    -2
      daemon/call_interfaces.c
  2. +2
    -2
      daemon/codec.c
  3. +72
    -70
      daemon/media_player.c
  4. +1
    -1
      daemon/mqtt.c
  5. +13
    -9
      include/media_player.h

+ 2
- 2
daemon/call_interfaces.c View File

@ -2937,8 +2937,8 @@ const char *call_play_media_ng(bencode_item_t *input, bencode_item_t *output) {
else
return "No media file specified";
if (l == monologues.head && monologue->player->duration)
bencode_dictionary_add_integer(output, "duration", monologue->player->duration);
if (l == monologues.head && monologue->player->coder.duration)
bencode_dictionary_add_integer(output, "duration", monologue->player->coder.duration);
}
return NULL;


+ 2
- 2
daemon/codec.c View File

@ -4826,8 +4826,8 @@ void codec_store_answer(struct codec_store *dst, struct codec_store *src, struct
// synthetic answer for T.38:
if (dst_media->type_id == MT_AUDIO && src_media->type_id == MT_IMAGE && dst->codec_prefs.length == 0) {
if (dst_media->t38_gateway && dst_media->t38_gateway->pcm_player
&& dst_media->t38_gateway->pcm_player->handler) {
codec_store_add_order(dst, &dst_media->t38_gateway->pcm_player->handler->dest_pt);
&& dst_media->t38_gateway->pcm_player->coder.handler) {
codec_store_add_order(dst, &dst_media->t38_gateway->pcm_player->coder.handler->dest_pt);
goto out;
}
}


+ 72
- 70
daemon/media_player.c View File

@ -60,27 +60,27 @@ static void media_player_shutdown(struct media_player *mp) {
//ilog(LOG_DEBUG, "shutting down media_player");
timerthread_obj_deschedule(&mp->tt_obj);
mp->next_run.tv_sec = 0;
avformat_close_input(&mp->fmtctx);
avformat_close_input(&mp->coder.fmtctx);
if (mp->sink) {
unsigned int num = send_timer_flush(mp->sink->send_timer, mp->handler);
unsigned int num = send_timer_flush(mp->sink->send_timer, mp->coder.handler);
ilog(LOG_DEBUG, "%u packets removed from send queue", num);
// roll back seq numbers already used
mp->ssrc_out->parent->seq_diff -= num;
}
mp->media = NULL;
codec_handler_free(&mp->handler);
if (mp->avioctx) {
if (mp->avioctx->buffer)
av_freep(&mp->avioctx->buffer);
av_freep(&mp->avioctx);
codec_handler_free(&mp->coder.handler);
if (mp->coder.avioctx) {
if (mp->coder.avioctx->buffer)
av_freep(&mp->coder.avioctx->buffer);
av_freep(&mp->coder.avioctx);
}
mp->avstream = NULL;
if (mp->blob)
free(mp->blob);
mp->blob = NULL;
mp->read_pos = STR_NULL;
mp->coder.avstream = NULL;
if (mp->coder.blob)
free(mp->coder.blob);
mp->coder.blob = NULL;
mp->coder.read_pos = STR_NULL;
}
#endif
@ -105,7 +105,7 @@ static void __media_player_free(void *p) {
ssrc_ctx_put(&mp->ssrc_out);
mutex_destroy(&mp->lock);
obj_put(mp->call);
av_packet_free(&mp->pkt);
av_packet_free(&mp->coder.pkt);
}
#endif
@ -132,9 +132,9 @@ struct media_player *media_player_new(struct call_monologue *ml) {
mp->seq = ssl_random();
mp->ssrc_out = ssrc_ctx;
mp->pkt = av_packet_alloc();
mp->pkt->data = NULL;
mp->pkt->size = 0;
mp->coder.pkt = av_packet_alloc();
mp->coder.pkt->data = NULL;
mp->coder.pkt->size = 0;
return mp;
#else
@ -320,17 +320,17 @@ int media_player_setup(struct media_player *mp, const struct rtp_payload_type *s
}
// if we already have a handler, see if anything needs changing
if (mp->handler) {
if (!rtp_payload_type_eq_exact(&mp->handler->dest_pt, dst_pt)
|| !rtp_payload_type_eq_exact(&mp->handler->source_pt, src_pt))
if (mp->coder.handler) {
if (!rtp_payload_type_eq_exact(&mp->coder.handler->dest_pt, dst_pt)
|| !rtp_payload_type_eq_exact(&mp->coder.handler->source_pt, src_pt))
{
ilog(LOG_DEBUG, "Resetting codec handler for media player");
codec_handler_free(&mp->handler);
codec_handler_free(&mp->coder.handler);
}
}
if (!mp->handler)
mp->handler = codec_handler_make_playback(src_pt, dst_pt, mp->sync_ts, mp->media);
if (!mp->handler)
if (!mp->coder.handler)
mp->coder.handler = codec_handler_make_playback(src_pt, dst_pt, mp->sync_ts, mp->media);
if (!mp->coder.handler)
return -1;
return 0;
@ -343,25 +343,26 @@ int media_player_setup(struct media_player *mp, const struct rtp_payload_type *s
#endif
static int __ensure_codec_handler(struct media_player *mp, const struct rtp_payload_type *dst_pt) {
if (mp->handler)
if (mp->coder.handler)
return 0;
// synthesise rtp payload type
struct rtp_payload_type src_pt = { .payload_type = -1 };
src_pt.codec_def = codec_find_by_av(mp->avstream->CODECPAR->codec_id);
src_pt.codec_def = codec_find_by_av(mp->coder.avstream->CODECPAR->codec_id);
if (!src_pt.codec_def) {
ilog(LOG_ERR, "Attempting to play media from an unsupported file format/codec");
return -1;
}
src_pt.encoding = src_pt.codec_def->rtpname_str;
src_pt.channels = GET_CHANNELS(mp->avstream->CODECPAR);
src_pt.clock_rate = mp->avstream->CODECPAR->sample_rate;
src_pt.channels = GET_CHANNELS(mp->coder.avstream->CODECPAR);
src_pt.clock_rate = mp->coder.avstream->CODECPAR->sample_rate;
codec_init_payload_type(&src_pt, MT_AUDIO);
if (media_player_setup(mp, &src_pt, dst_pt))
return -1;
mp->duration = mp->avstream->duration * 1000 * mp->avstream->time_base.num / mp->avstream->time_base.den;
mp->coder.duration = mp->coder.avstream->duration * 1000 * mp->coder.avstream->time_base.num
/ mp->coder.avstream->time_base.den;
payload_type_clear(&src_pt);
return 0;
@ -389,7 +390,7 @@ void media_player_add_packet(struct media_player *mp, char *buf, size_t len,
str_init_len(&packet.raw, buf, len);
packet.payload = packet.raw;
mp->handler->handler_func(mp->handler, &packet);
mp->coder.handler->handler_func(mp->coder.handler, &packet);
// as this is timing sensitive and we may have spent some time decoding,
// update our global "now" timestamp
@ -419,22 +420,22 @@ void media_player_add_packet(struct media_player *mp, char *buf, size_t len,
// appropriate lock must be held
static void media_player_read_packet(struct media_player *mp) {
if (!mp->fmtctx)
if (!mp->coder.fmtctx)
return;
int ret = av_read_frame(mp->fmtctx, mp->pkt);
int ret = av_read_frame(mp->coder.fmtctx, mp->coder.pkt);
if (ret < 0) {
if (ret == AVERROR_EOF) {
if (mp->repeat > 1){
ilog(LOG_DEBUG, "EOF reading from media stream but will repeat %li time",mp->repeat);
mp->repeat = mp->repeat - 1;
int64_t ret64 = avio_seek(mp->fmtctx->pb, 0, SEEK_SET);
int64_t ret64 = avio_seek(mp->coder.fmtctx->pb, 0, SEEK_SET);
if (ret64 != 0)
ilog(LOG_ERR, "Failed to seek to beginning of media file");
ret = av_seek_frame(mp->fmtctx, -1, 0, 0);
ret = av_seek_frame(mp->coder.fmtctx, -1, 0, 0);
if (ret < 0)
ilog(LOG_ERR, "Failed to seek to beginning of media file");
ret = av_read_frame(mp->fmtctx, mp->pkt);
ret = av_read_frame(mp->coder.fmtctx, mp->coder.pkt);
} else {
ilog(LOG_DEBUG, "EOF reading from media stream");
return;
@ -449,29 +450,30 @@ static void media_player_read_packet(struct media_player *mp) {
}
mp->last_frame_ts = mp->pkt->pts;
mp->last_frame_ts = mp->coder.pkt->pts;
// scale pts and duration according to sample rate
long long duration_scaled = mp->pkt->duration * mp->avstream->CODECPAR->sample_rate
* mp->avstream->time_base.num / mp->avstream->time_base.den;
unsigned long long pts_scaled = mp->pkt->pts * mp->avstream->CODECPAR->sample_rate
* mp->avstream->time_base.num / mp->avstream->time_base.den;
long long duration_scaled = mp->coder.pkt->duration * mp->coder.avstream->CODECPAR->sample_rate
* mp->coder.avstream->time_base.num / mp->coder.avstream->time_base.den;
unsigned long long pts_scaled = mp->coder.pkt->pts * mp->coder.avstream->CODECPAR->sample_rate
* mp->coder.avstream->time_base.num / mp->coder.avstream->time_base.den;
long long us_dur = mp->pkt->duration * 1000000LL * mp->avstream->time_base.num / mp->avstream->time_base.den;
long long us_dur = mp->coder.pkt->duration * 1000000LL * mp->coder.avstream->time_base.num
/ mp->coder.avstream->time_base.den;
ilog(LOG_DEBUG, "read media packet: pts %llu duration %lli (scaled %llu/%lli, %lli us), "
"sample rate %i, time_base %i/%i",
(unsigned long long) mp->pkt->pts,
(long long) mp->pkt->duration,
(unsigned long long) mp->coder.pkt->pts,
(long long) mp->coder.pkt->duration,
pts_scaled,
duration_scaled,
us_dur,
mp->avstream->CODECPAR->sample_rate,
mp->avstream->time_base.num, mp->avstream->time_base.den);
mp->coder.avstream->CODECPAR->sample_rate,
mp->coder.avstream->time_base.num, mp->coder.avstream->time_base.den);
media_player_add_packet(mp, (char *) mp->pkt->data, mp->pkt->size, us_dur, pts_scaled);
media_player_add_packet(mp, (char *) mp->coder.pkt->data, mp->coder.pkt->size, us_dur, pts_scaled);
av_packet_unref(mp->pkt);
av_packet_unref(mp->coder.pkt);
}
@ -518,10 +520,10 @@ static void media_player_play_start(struct media_player *mp, const struct rtp_pa
long long repeat, long long start_pos)
{
// needed to have usable duration for some formats. ignore errors.
avformat_find_stream_info(mp->fmtctx, NULL);
avformat_find_stream_info(mp->coder.fmtctx, NULL);
mp->avstream = mp->fmtctx->streams[0];
if (!mp->avstream) {
mp->coder.avstream = mp->coder.fmtctx->streams[0];
if (!mp->coder.avstream) {
ilog(LOG_ERR, "No AVStream present in format context");
return;
}
@ -535,7 +537,7 @@ static void media_player_play_start(struct media_player *mp, const struct rtp_pa
// if start_pos is positive, try to seek to that position
if (start_pos > 0) {
ilog(LOG_DEBUG, "Seeking to position %lli", start_pos);
av_seek_frame(mp->fmtctx, 0, start_pos, 0);
av_seek_frame(mp->coder.fmtctx, 0, start_pos, 0);
}
media_player_read_packet(mp);
mp->repeat = repeat;
@ -553,7 +555,7 @@ int media_player_play_file(struct media_player *mp, const str *file, long long r
char file_s[PATH_MAX];
snprintf(file_s, sizeof(file_s), STR_FORMAT, STR_FMT(file));
int ret = avformat_open_input(&mp->fmtctx, file_s, NULL, NULL);
int ret = avformat_open_input(&mp->coder.fmtctx, file_s, NULL, NULL);
if (ret < 0) {
ilog(LOG_ERR, "Failed to open media file for playback: %s", av_error(ret));
return -1;
@ -576,14 +578,14 @@ static int __mp_avio_read_wrap(void *opaque, uint8_t *buf, int buf_size) {
return AVERROR(EINVAL);
if (buf_size == 0)
return 0;
if (!mp->read_pos.len)
if (!mp->coder.read_pos.len)
return AVERROR_EOF;
int len = buf_size;
if (len > mp->read_pos.len)
len = mp->read_pos.len;
memcpy(buf, mp->read_pos.s, len);
str_shift(&mp->read_pos, len);
if (len > mp->coder.read_pos.len)
len = mp->coder.read_pos.len;
memcpy(buf, mp->coder.read_pos.s, len);
str_shift(&mp->coder.read_pos, len);
return len;
}
static int __mp_avio_read(void *opaque, uint8_t *buf, int buf_size) {
@ -596,8 +598,8 @@ static int64_t __mp_avio_seek_set(struct media_player *mp, int64_t offset) {
ilog(LOG_DEBUG, "__mp_avio_seek_set(%" PRIi64 ")", offset);
if (offset < 0)
return AVERROR(EINVAL);
mp->read_pos = *mp->blob;
if (str_shift(&mp->read_pos, offset))
mp->coder.read_pos = *mp->coder.blob;
if (str_shift(&mp->coder.read_pos, offset))
return AVERROR_EOF;
return offset;
}
@ -607,9 +609,9 @@ static int64_t __mp_avio_seek(void *opaque, int64_t offset, int whence) {
if (whence == SEEK_SET)
return __mp_avio_seek_set(mp, offset);
if (whence == SEEK_CUR)
return __mp_avio_seek_set(mp, ((int64_t) (mp->read_pos.s - mp->blob->s)) + offset);
return __mp_avio_seek_set(mp, ((int64_t) (mp->coder.read_pos.s - mp->coder.blob->s)) + offset);
if (whence == SEEK_END)
return __mp_avio_seek_set(mp, ((int64_t) mp->blob->len) + offset);
return __mp_avio_seek_set(mp, ((int64_t) mp->coder.blob->len) + offset);
return AVERROR(EINVAL);
}
#endif
@ -626,15 +628,15 @@ int media_player_play_blob(struct media_player *mp, const str *blob, long long r
if (!dst_pt)
return -1;
mp->blob = str_dup(blob);
mp->coder.blob = str_dup(blob);
err = "out of memory";
if (!mp->blob)
if (!mp->coder.blob)
goto err;
mp->read_pos = *mp->blob;
mp->coder.read_pos = *mp->coder.blob;
err = "could not allocate AVFormatContext";
mp->fmtctx = avformat_alloc_context();
if (!mp->fmtctx)
mp->coder.fmtctx = avformat_alloc_context();
if (!mp->coder.fmtctx)
goto err;
void *avio_buf = av_malloc(DEFAULT_AVIO_BUFSIZE);
@ -642,17 +644,17 @@ int media_player_play_blob(struct media_player *mp, const str *blob, long long r
if (!avio_buf)
goto err;
mp->avioctx = avio_alloc_context(avio_buf, DEFAULT_AVIO_BUFSIZE, 0, mp, __mp_avio_read,
mp->coder.avioctx = avio_alloc_context(avio_buf, DEFAULT_AVIO_BUFSIZE, 0, mp, __mp_avio_read,
NULL, __mp_avio_seek);
err = "failed to allocate AVIOContext";
if (!mp->avioctx)
if (!mp->coder.avioctx)
goto err;
mp->fmtctx->pb = mp->avioctx;
mp->coder.fmtctx->pb = mp->coder.avioctx;
// consumes allocated mp->fmtctx
// consumes allocated mp->coder.fmtctx
err = "failed to open AVFormatContext input";
av_ret = avformat_open_input(&mp->fmtctx, "dummy", NULL, NULL);
av_ret = avformat_open_input(&mp->coder.fmtctx, "dummy", NULL, NULL);
if (av_ret < 0)
goto err;


+ 1
- 1
daemon/mqtt.c View File

@ -172,7 +172,7 @@ static void mqtt_monologue_stats(struct call_monologue *ml, JsonBuilder *json) {
json_builder_begin_object(json);
json_builder_set_member_name(json, "duration");
json_builder_add_int_value(json, mp->duration);
json_builder_add_int_value(json, mp->coder.duration);
json_builder_set_member_name(json, "repeat");
json_builder_add_int_value(json, mp->repeat);
json_builder_set_member_name(json, "frame_time");


+ 13
- 9
include/media_player.h View File

@ -28,6 +28,17 @@ struct rtp_payload_type;
typedef void (*media_player_run_func)(struct media_player *);
struct media_player_coder {
AVFormatContext *fmtctx;
AVStream *avstream;
unsigned long duration; // in milliseconds
AVPacket *pkt;
AVIOContext *avioctx;
str *blob;
str read_pos;
struct codec_handler *handler;
};
struct media_player {
struct timerthread_obj tt_obj;
mutex_t lock;
@ -41,20 +52,13 @@ struct media_player {
struct timeval next_run;
unsigned long repeat;
AVFormatContext *fmtctx;
AVStream *avstream;
unsigned long duration; // in milliseconds
AVPacket *pkt;
struct codec_handler *handler;
struct media_player_coder coder;
struct ssrc_ctx *ssrc_out;
unsigned long seq;
unsigned long sync_ts;
struct timeval sync_ts_tv;
long long last_frame_ts;
AVIOContext *avioctx;
str *blob;
str read_pos;
};
INLINE void media_player_put(struct media_player **mp) {


Loading…
Cancel
Save