|
|
@ -14,6 +14,10 @@ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define DEFAULT_AVIO_BUFSIZE 4096 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static struct timerthread media_player_thread; |
|
|
static struct timerthread media_player_thread; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -22,8 +26,7 @@ static struct timerthread media_player_thread; |
|
|
static void media_player_shutdown(struct media_player *mp) { |
|
|
static void media_player_shutdown(struct media_player *mp) { |
|
|
ilog(LOG_DEBUG, "shutting down media_player"); |
|
|
ilog(LOG_DEBUG, "shutting down media_player"); |
|
|
timerthread_obj_deschedule(&mp->tt_obj); |
|
|
timerthread_obj_deschedule(&mp->tt_obj); |
|
|
avformat_free_context(mp->fmtctx); |
|
|
|
|
|
mp->fmtctx = NULL; |
|
|
|
|
|
|
|
|
avformat_close_input(&mp->fmtctx); |
|
|
mp->media = NULL; |
|
|
mp->media = NULL; |
|
|
if (mp->handler) |
|
|
if (mp->handler) |
|
|
codec_handler_free(mp->handler); |
|
|
codec_handler_free(mp->handler); |
|
|
@ -31,6 +34,15 @@ static void media_player_shutdown(struct media_player *mp) { |
|
|
if (mp->ssrc_out) |
|
|
if (mp->ssrc_out) |
|
|
obj_put(&mp->ssrc_out->parent->h); |
|
|
obj_put(&mp->ssrc_out->parent->h); |
|
|
mp->ssrc_out = NULL; |
|
|
mp->ssrc_out = NULL; |
|
|
|
|
|
if (mp->avioctx) { |
|
|
|
|
|
if (mp->avioctx->buffer) |
|
|
|
|
|
av_freep(&mp->avioctx->buffer); |
|
|
|
|
|
av_freep(&mp->avioctx); |
|
|
|
|
|
} |
|
|
|
|
|
if (mp->blob) |
|
|
|
|
|
free(mp->blob); |
|
|
|
|
|
mp->blob = NULL; |
|
|
|
|
|
mp->read_pos = STR_NULL; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -239,8 +251,96 @@ int media_player_play_file(struct media_player *mp, const str *file) { |
|
|
|
|
|
|
|
|
media_player_play_start(mp); |
|
|
media_player_play_start(mp); |
|
|
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int __mp_avio_read_wrap(void *opaque, uint8_t *buf, int buf_size) { |
|
|
|
|
|
struct media_player *mp = opaque; |
|
|
|
|
|
if (buf_size < 0) |
|
|
|
|
|
return AVERROR(EINVAL); |
|
|
|
|
|
if (buf_size == 0) |
|
|
|
|
|
return 0; |
|
|
|
|
|
if (!mp->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); |
|
|
|
|
|
return len; |
|
|
|
|
|
} |
|
|
|
|
|
static int __mp_avio_read(void *opaque, uint8_t *buf, int buf_size) { |
|
|
|
|
|
ilog(LOG_DEBUG, "__mp_avio_read(%i)", buf_size); |
|
|
|
|
|
int ret = __mp_avio_read_wrap(opaque, buf, buf_size); |
|
|
|
|
|
ilog(LOG_DEBUG, "__mp_avio_read(%i) = %i", buf_size, ret); |
|
|
|
|
|
return ret; |
|
|
|
|
|
} |
|
|
|
|
|
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)) |
|
|
|
|
|
return AVERROR_EOF; |
|
|
|
|
|
return offset; |
|
|
|
|
|
} |
|
|
|
|
|
static int64_t __mp_avio_seek(void *opaque, int64_t offset, int whence) { |
|
|
|
|
|
ilog(LOG_DEBUG, "__mp_avio_seek(%" PRIi64 ", %i)", offset, whence); |
|
|
|
|
|
struct media_player *mp = opaque; |
|
|
|
|
|
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); |
|
|
|
|
|
if (whence == SEEK_END) |
|
|
|
|
|
return __mp_avio_seek_set(mp, ((int64_t) mp->blob->len) + offset); |
|
|
|
|
|
return AVERROR(EINVAL); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// call->master_lock held in W |
|
|
|
|
|
int media_player_play_blob(struct media_player *mp, const str *blob) { |
|
|
|
|
|
const char *err; |
|
|
|
|
|
|
|
|
|
|
|
if (media_player_play_init(mp)) |
|
|
|
|
|
return -1; |
|
|
|
|
|
|
|
|
|
|
|
mp->blob = str_dup(blob); |
|
|
|
|
|
err = "out of memory"; |
|
|
|
|
|
if (!mp->blob) |
|
|
|
|
|
goto err; |
|
|
|
|
|
mp->read_pos = *mp->blob; |
|
|
|
|
|
|
|
|
|
|
|
err = "could not allocate AVFormatContext"; |
|
|
|
|
|
mp->fmtctx = avformat_alloc_context(); |
|
|
|
|
|
if (!mp->fmtctx) |
|
|
|
|
|
goto err; |
|
|
|
|
|
|
|
|
|
|
|
void *avio_buf = av_malloc(DEFAULT_AVIO_BUFSIZE); |
|
|
|
|
|
err = "failed to allocate AVIO buffer"; |
|
|
|
|
|
if (!avio_buf) |
|
|
|
|
|
goto err; |
|
|
|
|
|
|
|
|
|
|
|
mp->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) |
|
|
|
|
|
goto err; |
|
|
|
|
|
|
|
|
|
|
|
mp->fmtctx->pb = mp->avioctx; |
|
|
|
|
|
|
|
|
|
|
|
// consumes allocated mp->fmtctx |
|
|
|
|
|
int ret = avformat_open_input(&mp->fmtctx, "dummy", NULL, NULL); |
|
|
|
|
|
if (ret < 0) |
|
|
|
|
|
return -1; |
|
|
|
|
|
|
|
|
|
|
|
media_player_play_start(mp); |
|
|
|
|
|
|
|
|
return 0; |
|
|
return 0; |
|
|
|
|
|
|
|
|
|
|
|
err: |
|
|
|
|
|
ilog(LOG_ERR, "Failed to start media playback from memory: %s", err); |
|
|
|
|
|
return -1; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|