diff options
author | Anton Khirnov <anton@khirnov.net> | 2011-07-07 15:34:56 +0200 |
---|---|---|
committer | Anton Khirnov <anton@khirnov.net> | 2011-10-11 08:35:01 +0200 |
commit | 952dc04531f06716b9286aafaa3ee76766075950 (patch) | |
tree | 9755a9fdf989cbcb5f5b583357b64b99e0901802 | |
parent | 7bb1807c2dd9623842f1c6d454e7f2892b5bc8d7 (diff) |
lavf: add a basic API for playlist input.
-rw-r--r-- | libavformat/Makefile | 1 | ||||
-rw-r--r-- | libavformat/avformat.h | 58 | ||||
-rw-r--r-- | libavformat/playlist.c | 110 | ||||
-rw-r--r-- | libavformat/playlist.h | 33 | ||||
-rw-r--r-- | libavformat/utils.c | 23 |
5 files changed, 224 insertions, 1 deletions
diff --git a/libavformat/Makefile b/libavformat/Makefile index 0a30c6ec1a..10943605d2 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -10,6 +10,7 @@ OBJS = allformats.o \ metadata.o \ options.o \ os_support.o \ + playlist.o \ sdp.o \ seek.o \ utils.o \ diff --git a/libavformat/avformat.h b/libavformat/avformat.h index cc5457e8a2..ee82f5018d 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -182,6 +182,58 @@ attribute_deprecated void av_metadata_free(AVDictionary **m); */ #endif +/** + * @defgroup playlist_api Public Playlist API + * @{ + * Playlist files work differently from "normal" media files in that they + * don't contain actual playable data, only links to it. When libavformat + * opens a playlist, it will create and populate the AVFormatContext.plist + * field. + * + * Each playlist element contains one or more URLs pointing to media files + * to be played. Multiple URLs under one entry should point to different + * copies/versions of the same content. + * + * Opening/closing the playlist contents and reading the contents is up to + * the caller. A convenience function av_playlist_advance() is provided to + * simplify this. AVPlaylistContext.cur_elem and AVPlaylistElement.fc fields + * are managed by this function and are unset if the caller chooses not to + * use it. + */ + +typedef struct AVPlaylistElement { + uint8_t **filenames; /** A list of URLs for this element in the order of preference. */ + int nb_filenames; /** Number of filenames. */ + AVDictionary *metadata; + + int64_t start, end; /** Start and end times for this element in AV_TIME_BASE units. + AV_NOPTS_VALUE if unspecified. */ + + struct AVFormatContext *fc; /** AVFormatContext for this element. */ +} AVPlaylistElement; + +typedef struct AVPlaylistContext { + AVPlaylistElement **elems; + int nb_elems; + + int cur_elem; +} AVPlaylistContext; + +/** + * Close current open element in the playlist (if any) and advance to another + * one. + * + * @param s the playlist in which to advance + * @param offset opened element will be offset elements from current. + * @param options options to pass to avformat_open_input(). + * + * @return index of the opened element on success, a negative number on error. + */ +int av_playlist_advance(struct AVFormatContext *s, int offset, AVDictionary **options); + +/** + * @} + */ /* packet functions */ @@ -870,6 +922,12 @@ typedef struct AVFormatContext { * - decoding: Set by user. */ int error_recognition; + + /* + * If this stream is a playlist, this holds the playlist-relevant + * data. NULL otherwise. + */ + AVPlaylistContext *plist; } AVFormatContext; typedef struct AVPacketList { diff --git a/libavformat/playlist.c b/libavformat/playlist.c new file mode 100644 index 0000000000..db91a7ca73 --- /dev/null +++ b/libavformat/playlist.c @@ -0,0 +1,110 @@ +/* + * Internal playlist functions. + * Copyright (c) 2011 Anton Khirnov + * + * This file is part of Libav. + * + * Libav is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * Libav is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avformat.h" +#include "internal.h" +#include "playlist.h" +#include "libavutil/mem.h" + +AVPlaylistContext *ff_playlist_alloc(void) +{ + AVPlaylistContext *p = av_mallocz(sizeof(*p)); + if (!p) + return NULL; + + p->cur_elem = -1; + + return p; +} + +void ff_playlist_free(AVPlaylistContext **pls) +{ + AVPlaylistContext *p = *pls; + + if (p) { + while (p->nb_elems--) { + AVPlaylistElement *e = p->elems[p->nb_elems]; + while (e->nb_filenames--) + av_freep(&e->filenames[e->nb_filenames]); + av_freep(&e->filenames); + av_freep(&p->elems[p->nb_elems]); + } + av_freep(pls); + } +} + +AVPlaylistElement *ff_playlist_add_entry(AVFormatContext *s, const uint8_t *filename) +{ + AVPlaylistElement *elem; + uint8_t *tmp; + + if (!s->plist && !(s->plist = ff_playlist_alloc())) + return NULL; + + if (!(elem = av_mallocz(sizeof(*elem)))) + return NULL; + tmp = av_strdup(filename); + dynarray_add(&elem->filenames, &elem->nb_filenames, tmp); + dynarray_add(&s->plist->elems, &s->plist->nb_elems, elem); + return elem; +} + +int av_playlist_advance(AVFormatContext *s, int offset, AVDictionary **options) +{ + AVPlaylistContext *plist = s->plist; + AVPlaylistElement *elem; + int ret, i; + + if (!plist) + return AVERROR(EINVAL); + + if (plist->cur_elem >= 0) { + av_close_input_file(plist->elems[plist->cur_elem]->fc); + plist->elems[plist->cur_elem]->fc = NULL; + plist->cur_elem += offset; + } else + plist->cur_elem = (offset >= 0 ? -1 : plist->nb_elems) + offset; + + if (plist->cur_elem >= plist->nb_elems || plist->cur_elem < 0) { + plist->cur_elem = -1; + return AVERROR_EOF; + } + + elem = plist->elems[plist->cur_elem]; + for (i = 0; i < elem->nb_filenames; i++) { + AVDictionary *tmp = NULL; + + if (options && i + 1 < elem->nb_filenames) + av_dict_copy(&tmp, *options, 0); // save the options for the next attempt if needed + + ret = avformat_open_input(&elem->fc, plist->elems[plist->cur_elem]->filenames[i], + NULL, options); + if (ret >= 0) { + av_dict_free(&tmp); + return plist->cur_elem; + } + av_dict_free(options); + *options = tmp; + } + av_log(s, AV_LOG_ERROR, "Could not open element %d.\n", plist->cur_elem); + plist->cur_elem = -1; + return ret; +} diff --git a/libavformat/playlist.h b/libavformat/playlist.h new file mode 100644 index 0000000000..074713277c --- /dev/null +++ b/libavformat/playlist.h @@ -0,0 +1,33 @@ +/* + * Internal playlist header. + * Copyright (c) 2011 Anton Khirnov + * + * This file is part of Libav. + * + * Libav is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * Libav is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVFORMAT_PLAYLIST_H +#define AVFORMAT_PLAYLIST_H + +#include "avformat.h" + +AVPlaylistContext *ff_playlist_alloc(void); + +void ff_playlist_free(AVPlaylistContext **pls); + +AVPlaylistElement *ff_playlist_add_entry(AVFormatContext *s, const uint8_t *filename); + +#endif // AVFORMAT_PLAYLIST_H diff --git a/libavformat/utils.c b/libavformat/utils.c index e4e6d24e53..bcd26668ca 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -30,6 +30,7 @@ #include "libavutil/pixdesc.h" #include "metadata.h" #include "id3v2.h" +#include "playlist.h" #include "libavutil/avstring.h" #include "libavutil/mathematics.h" #include "riff.h" @@ -2596,6 +2597,15 @@ int av_read_pause(AVFormatContext *s) void av_close_input_stream(AVFormatContext *s) { + if (s->plist) { + int i; + for (i = 0; i < s->plist->nb_elems; i++) + if (s->plist->elems[i]->fc) { + av_close_input_file(s->plist->elems[i]->fc); + s->plist->elems[i]->fc = NULL; + } + ff_playlist_free(&s->plist); + } flush_packet_queue(s); if (s->iformat->read_close) s->iformat->read_close(s); @@ -3332,7 +3342,7 @@ void av_dump_format(AVFormatContext *ic, const char *url, int is_output) { - int i; + int i, j; uint8_t *printed = ic->nb_streams ? av_mallocz(ic->nb_streams) : NULL; if (ic->nb_streams && !printed) return; @@ -3343,6 +3353,17 @@ void av_dump_format(AVFormatContext *ic, is_output ? ic->oformat->name : ic->iformat->name, is_output ? "to" : "from", url); dump_metadata(NULL, ic->metadata, " "); + if (ic->plist) { + av_log(NULL, AV_LOG_INFO, " Playlist:\n"); + for (i = 0; i < ic->plist->nb_elems; i++) { + AVPlaylistElement *elem = ic->plist->elems[i]; + av_log(NULL, AV_LOG_INFO, " Element #%d:", i); + for (j = 0; j < elem->nb_filenames; j++) + av_log(NULL, AV_LOG_INFO, " %s\n", elem->filenames[j]); + dump_metadata(NULL, elem->metadata, " "); + } + return; + } if (!is_output) { av_log(NULL, AV_LOG_INFO, " Duration: "); if (ic->duration != AV_NOPTS_VALUE) { |