aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Khirnov <anton@khirnov.net>2011-07-07 15:34:56 +0200
committerAnton Khirnov <anton@khirnov.net>2011-10-11 08:35:01 +0200
commit952dc04531f06716b9286aafaa3ee76766075950 (patch)
tree9755a9fdf989cbcb5f5b583357b64b99e0901802
parent7bb1807c2dd9623842f1c6d454e7f2892b5bc8d7 (diff)
lavf: add a basic API for playlist input.
-rw-r--r--libavformat/Makefile1
-rw-r--r--libavformat/avformat.h58
-rw-r--r--libavformat/playlist.c110
-rw-r--r--libavformat/playlist.h33
-rw-r--r--libavformat/utils.c23
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) {