[FFmpeg-soc] [soc]: r4321 - in concat/libavformat: . m3u.c playlist.c playlist.h

gkovacs subversion at mplayerhq.hu
Sat May 30 02:20:08 CEST 2009


Author: gkovacs
Date: Sat May 30 02:20:08 2009
New Revision: 4321

Log:
added initial playlist infrastructure with simple m3u demuxer, tested mostly with ffplay

Added:
   concat/libavformat/
   concat/libavformat/m3u.c
   concat/libavformat/playlist.c
   concat/libavformat/playlist.h

Added: concat/libavformat/m3u.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ concat/libavformat/m3u.c	Sat May 30 02:20:08 2009	(r4321)
@@ -0,0 +1,245 @@
+/*
+ * M3U muxer and demuxer
+ * Copyright (c) 2001 Geza Kovacs
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * Based on AU muxer and demuxer in au.c
+ */
+
+#include "avformat.h"
+#include "raw.h"
+#include "riff.h"
+#include "playlist.h"
+
+/* if we don't know the size in advance */
+#define M3U_UNKNOWN_SIZE ((uint32_t)(~0))
+
+/* The ffmpeg codecs we support, and the IDs they have in the file */
+static const AVCodecTag codec_m3u_tags[] = {
+    { CODEC_ID_PCM_MULAW, 1 },
+    { CODEC_ID_PCM_S8, 2 },
+    { CODEC_ID_PCM_S16BE, 3 },
+    { CODEC_ID_PCM_S24BE, 4 },
+    { CODEC_ID_PCM_S32BE, 5 },
+    { CODEC_ID_PCM_F32BE, 6 },
+    { CODEC_ID_PCM_F64BE, 7 },
+    { CODEC_ID_PCM_ALAW, 27 },
+    { 0, 0 },
+};
+
+
+
+#if CONFIG_PLAYLIST_MUXER
+/* AUDIO_FILE header */
+static int put_m3u_header(ByteIOContext *pb, AVCodecContext *enc)
+{
+    if(!enc->codec_tag)
+        return -1;
+    put_tag(pb, ".snd");       /* magic number */
+    put_be32(pb, 24);           /* header size */
+    put_be32(pb, M3U_UNKNOWN_SIZE); /* data size */
+    put_be32(pb, (uint32_t)enc->codec_tag);     /* codec ID */
+    put_be32(pb, enc->sample_rate);
+    put_be32(pb, (uint32_t)enc->channels);
+    return 0;
+}
+
+static int m3u_write_header(AVFormatContext *s)
+{
+    ByteIOContext *pb = s->pb;
+
+    s->priv_data = NULL;
+
+    /* format header */
+    if (put_m3u_header(pb, s->streams[0]->codec) < 0) {
+        return -1;
+    }
+
+    put_flush_packet(pb);
+
+    return 0;
+}
+
+static int m3u_write_packet(AVFormatContext *s, AVPacket *pkt)
+{
+    ByteIOContext *pb = s->pb;
+    put_buffer(pb, pkt->data, pkt->size);
+    return 0;
+}
+
+static int m3u_write_trailer(AVFormatContext *s)
+{
+    ByteIOContext *pb = s->pb;
+    int64_t file_size;
+
+    if (!url_is_streamed(s->pb)) {
+
+        /* update file size */
+        file_size = url_ftell(pb);
+        url_fseek(pb, 8, SEEK_SET);
+        put_be32(pb, (uint32_t)(file_size - 24));
+        url_fseek(pb, file_size, SEEK_SET);
+
+        put_flush_packet(pb);
+    }
+
+    return 0;
+}
+#endif /* CONFIG_M3U_MUXER */
+
+
+
+static int compare_bufs(unsigned char *buf, unsigned char *rbuf)
+{
+    while (*rbuf != 0)
+    {
+        if (*rbuf != *buf)
+            return 0;
+        ++buf;
+        ++rbuf;
+    }
+    return 1;
+}
+
+static int m3u_probe(AVProbeData *p)
+{
+    if (p->buf_size >= 7 && p->buf != 0)
+    {
+        if (compare_bufs(p->buf, "#EXTM3U"))
+            return AVPROBE_SCORE_MAX;
+        else
+            return 0;
+    }
+    if (check_file_extn(p->filename, "m3u"))
+        return AVPROBE_SCORE_MAX/2;
+    else
+        return 0;
+}
+
+static int m3u_list_files(unsigned char *buffer, int buffer_size, unsigned char **file_list, unsigned int *lfx_ptr)
+{
+    unsigned int i;
+    unsigned int lfx = 0;
+    unsigned int fx = 0;
+    unsigned char hashed_out = 0;
+    unsigned char fldata[262144];
+    memset(fldata, 0, 262144);
+    memset(file_list, 0, 512 * sizeof(unsigned char*));
+    for (i = 0; i < 512; ++i)
+    {
+        file_list[i] = fldata+i*512;
+    }
+    for (i = 0; i < buffer_size; ++i)
+    {
+        if (buffer[i] == 0)
+            break;
+        if (buffer[i] == '#')
+        {
+            hashed_out = 1;
+            continue;
+        }
+        if (buffer[i] == '\n')
+        {
+            hashed_out = 0;
+            if (fx != 0)
+            {
+                fx = 0;
+                ++lfx;
+            }
+            continue;
+        }
+        if (hashed_out)
+            continue;
+        file_list[lfx][fx] = buffer[i];
+        ++fx;
+    }
+    *lfx_ptr = lfx;
+    return 0;
+}
+
+
+
+/* m3u input */
+static int m3u_read_header(AVFormatContext *s,
+                          AVFormatParameters *ap)
+{
+    unsigned char *flist[512];
+    int flist_len;
+    ByteIOContext *pb;
+    PlaylistD *playld;
+    pb = s->pb;
+    m3u_list_files(pb->buffer, pb->buffer_size, flist, &flist_len);
+    playld = av_make_playlistd(flist, flist_len);
+    s->priv_data = playld;
+    playlist_populate_context(playld, s);
+    return 0;
+}
+
+#define MAX_SIZE 4096
+
+static int m3u_read_packet(AVFormatContext *s,
+                          AVPacket *pkt)
+{
+    int ret;
+    PlaylistD *playld;
+    AVFormatContext *ic;
+    playld = s->priv_data;
+    retr:
+    ic = playld->pelist[playld->pe_curidx]->ic;
+    ret = ic->iformat->read_packet(ic, pkt);
+    if (ret < 0 && playld->pe_curidx < playld->pelist_size - 1)
+    {
+        ++playld->pe_curidx;
+        // TODO clear all existing streams before repopulating
+        playlist_populate_context(playld, s);
+        goto retr;
+    }
+    return ret;
+}
+
+#if CONFIG_M3U_DEMUXER
+AVInputFormat m3u_demuxer = {
+    "m3u",
+    NULL_IF_CONFIG_SMALL("M3U format"),
+    0,
+    m3u_probe,
+    m3u_read_header,
+    m3u_read_packet,
+    NULL,
+    pcm_read_seek,
+    .codec_tag= (const AVCodecTag* const []){codec_m3u_tags, 0},
+};
+#endif
+
+#if CONFIG_M3U_MUXER
+AVOutputFormat m3u_muxer = {
+    "m3u",
+    NULL_IF_CONFIG_SMALL("M3U format"),
+    "audio/x-mpegurl",
+    "m3u",
+    0,
+    CODEC_ID_PCM_S16BE,
+    CODEC_ID_NONE,
+    m3u_write_header,
+    m3u_write_packet,
+    m3u_write_trailer,
+    .codec_tag= (const AVCodecTag* const []){codec_m3u_tags, 0},
+};
+#endif //CONFIG_M3U_MUXER

Added: concat/libavformat/playlist.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ concat/libavformat/playlist.c	Sat May 30 02:20:08 2009	(r4321)
@@ -0,0 +1,167 @@
+/*
+ * M3U muxer and demuxer
+ * Copyright (c) 2001 Geza Kovacs
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * Based on AU muxer and demuxer in au.c
+ */
+
+#include "avformat.h"
+#include "playlist.h"
+
+int av_open_input_playelem(PlayElem *pe)
+{
+    return av_open_input_file(&(pe->ic), pe->filename, pe->fmt, pe->buf_size, pe->ap);
+}
+
+
+// based on decode_thread() in ffplay.c
+int av_alloc_playelem(unsigned char *filename, PlayElem *pe)
+{
+//    AVProbeData *pd;
+    AVFormatContext *ic;
+    AVFormatParameters *ap;
+//    pd = av_malloc(sizeof(AVProbeData));
+//    ic = av_malloc(sizeof(AVFormatContext));
+    ap = av_malloc(sizeof(AVFormatParameters));
+    memset(ap, 0, sizeof(AVFormatParameters));
+    ap->width = 0;
+    ap->height = 0;
+    ap->time_base = (AVRational){1, 25};
+    ap->pix_fmt = 0;
+//    pd->filename = filename;
+//    pd->buf = NULL;
+//    pd->buf_size = 0;
+    pe->ic = ic;
+    pe->filename = filename;
+    pe->fmt = 0;
+    pe->buf_size = 0;
+    pe->ap = ap;
+//    pe->fmt = pe->ic->iformat;
+    return 0;
+}
+
+PlayElem* av_make_playelem(unsigned char *filename)
+{
+    int err;
+    PlayElem *pe = av_malloc(sizeof(PlayElem));
+    err = av_alloc_playelem(filename, pe);
+    if (err < 0)
+        print_error("during-av_alloc_playelem", err);
+    err = av_open_input_playelem(pe);
+    if (err < 0)
+        print_error("during-open_input_playelem", err);
+    pe->fmt = pe->ic->iformat;
+    if (!pe->fmt)
+    {
+        fprintf(stderr, "pefmt not set\n");
+        fflush(stderr);
+    }
+    err = av_find_stream_info(pe->ic);
+    if (err < 0)
+    {
+        fprintf(stderr, "failed codec probe av_find_stream_info");
+        fflush(stderr);
+    }
+    if(pe->ic->pb)
+    {
+        pe->ic->pb->eof_reached = 0;
+    }
+    else
+    {
+        fprintf(stderr, "failed pe ic pb not set");
+        fflush(stderr);
+    }
+    if(!pe->fmt)
+    {
+        fprintf(stderr, "failed pe ic fmt not set");
+        fflush(stderr);
+    }
+    return pe;
+}
+
+PlaylistD* av_make_playlistd(unsigned char **flist, int flist_len)
+{
+    int i;
+    PlaylistD *playld = av_malloc(sizeof(PlaylistD));
+    playld->pe_curidx = 0;
+    playld->pelist_size = flist_len;
+    playld->pelist = av_malloc(playld->pelist_size * sizeof(PlayElem*));
+    memset(playld->pelist, 0, playld->pelist_size * sizeof(PlayElem*));
+    for (int i = 0; i < playld->pelist_size; ++i)
+    {
+        playld->pelist[i] = av_make_playelem(flist[i]);
+    }
+    return playld;
+}
+
+int playlist_populate_context(PlaylistD *playld, AVFormatContext *s)
+{
+    int i;
+    AVFormatContext *ic = playld->pelist[playld->pe_curidx]->ic;
+    AVFormatParameters *nap = playld->pelist[playld->pe_curidx]->ap;
+    ic->iformat->read_header(ic, nap);
+    s->nb_streams = ic->nb_streams;
+    for (i = 0; i < ic->nb_streams; ++i)
+    {
+        s->streams[i] = ic->streams[i];
+    }
+    return 0;
+}
+
+int check_file_extn(char *cch, char *extn)
+{
+    int pos;
+    int extnl;
+    pos = -1;
+    extnl = 0;
+    while (extn[extnl] != 0)
+       ++extnl;
+    pos = -1;
+    if (!cch)
+    {
+        return 0;
+    }
+    if (*cch == 0)
+    {
+        return 0;
+    }
+    while (*cch != 0)
+    {
+        if (*cch == '.')
+        {
+            pos = 0;
+        }
+        else if (pos >= 0)
+        {
+            if (*cch == extn[pos])
+                ++pos;
+            else
+                pos = -1;
+            if (pos == extnl)
+            {
+                return 1;
+            }
+        }
+        ++cch;
+    }
+    return 0;
+}
+

Added: concat/libavformat/playlist.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ concat/libavformat/playlist.h	Sat May 30 02:20:08 2009	(r4321)
@@ -0,0 +1,50 @@
+/*
+ * M3U muxer and demuxer
+ * Copyright (c) 2001 Geza Kovacs
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * Based on AU muxer and demuxer in au.c
+ */
+
+
+typedef struct PlayElem {
+    AVFormatContext *ic;
+    char *filename;
+    AVInputFormat *fmt;
+    int buf_size;
+    AVFormatParameters *ap;
+} PlayElem;
+
+typedef struct PlaylistD {
+    PlayElem **pelist;
+    int pelist_size;
+    int pe_curidx;
+} PlaylistD;
+
+int av_open_input_playelem(PlayElem *pe);
+
+PlayElem* av_make_playelem(unsigned char *filename);
+
+PlaylistD* av_make_playlistd(unsigned char **flist, int flist_len);
+
+int check_file_extn(char *cch, char *extn);
+
+int playlist_populate_context(PlaylistD *playld, AVFormatContext *s);
+


More information about the FFmpeg-soc mailing list