Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
M
mpd
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Иван Мажукин
mpd
Commits
efc885a9
Commit
efc885a9
authored
Dec 30, 2009
by
Max Kellermann
Browse files
Options
Browse Files
Download
Plain Diff
Merge vorbis+icy fixes from branch 'v0.15.x'
Conflicts: Makefile.am NEWS configure.ac src/input/curl_input_plugin.c src/input_stream.c
parents
333e11d0
4419e5b9
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
354 additions
and
183 deletions
+354
-183
Makefile.am
Makefile.am
+4
-1
NEWS
NEWS
+7
-0
ffmpeg_plugin.c
src/decoder/ffmpeg_plugin.c
+5
-0
flac_plugin.c
src/decoder/flac_plugin.c
+8
-2
oggflac_plugin.c
src/decoder/oggflac_plugin.c
+3
-1
vorbis_plugin.c
src/decoder/vorbis_plugin.c
+6
-1
curl_input_plugin.c
src/input/curl_input_plugin.c
+19
-178
curl_input_plugin.h
src/input/curl_input_plugin.h
+10
-0
rewind_input_plugin.c
src/input/rewind_input_plugin.c
+240
-0
rewind_input_plugin.h
src/input/rewind_input_plugin.h
+49
-0
input_stream.c
src/input_stream.c
+3
-0
No files found.
Makefile.am
View file @
efc885a9
...
...
@@ -99,6 +99,7 @@ mpd_headers = \
src/input_stream.h
\
src/input/file_input_plugin.h
\
src/input/curl_input_plugin.h
\
src/input/rewind_input_plugin.h
\
src/input/mms_input_plugin.h
\
src/text_file.h
\
src/text_input_stream.h
\
...
...
@@ -584,7 +585,9 @@ INPUT_SRC = \
src/input/file_input_plugin.c
if
ENABLE_CURL
INPUT_SRC
+=
src/input/curl_input_plugin.c src/icy_metadata.c
INPUT_SRC
+=
src/input/curl_input_plugin.c
\
src/input/rewind_input_plugin.c
\
src/icy_metadata.c
endif
if
ENABLE_MMS
...
...
NEWS
View file @
efc885a9
...
...
@@ -83,6 +83,13 @@ ver 0.16 (20??/??/??)
* require GLib 2.12
ver 0.15.8 (2009/??/??)
* input:
- curl: allow rewinding with Icy-Metadata
* decoders:
- ffmpeg, flac, vorbis: added more flac/vorbis MIME types
ver 0.15.7 (2009/12/27)
* archive:
- close archive when stream is closed
...
...
src/decoder/ffmpeg_plugin.c
View file @
efc885a9
...
...
@@ -481,6 +481,7 @@ static const char *const ffmpeg_mime_types[] = {
"application/ogg"
,
"application/x-ms-wmz"
,
"application/x-ms-wmd"
,
"application/x-ogg"
,
"application/x-shockwave-flash"
,
"application/x-shorten"
,
"audio/8svx"
,
...
...
@@ -495,6 +496,7 @@ static const char *const ffmpeg_mime_types[] = {
"audio/ogg"
,
"audio/qcelp"
,
"audio/vorbis"
,
"audio/vorbis+ogg"
,
"audio/x-8svx"
,
"audio/x-16sv"
,
"audio/x-aac"
,
...
...
@@ -512,6 +514,9 @@ static const char *const ffmpeg_mime_types[] = {
"audio/x-ms-wma"
,
"audio/x-ms-wax"
,
"audio/x-musepack"
,
"audio/x-ogg"
,
"audio/x-vorbis"
,
"audio/x-vorbis+ogg"
,
"audio/x-pn-realaudio"
,
"audio/x-pn-multirate-realaudio"
,
"audio/x-speex"
,
...
...
src/decoder/flac_plugin.c
View file @
efc885a9
...
...
@@ -791,9 +791,11 @@ oggflac_decode(struct decoder *decoder, struct input_stream *input_stream)
static
const
char
*
const
oggflac_suffixes
[]
=
{
"ogg"
,
"oga"
,
NULL
};
static
const
char
*
const
oggflac_mime_types
[]
=
{
"audio/x-flac+ogg"
,
"application/ogg"
,
"application/x-ogg"
,
"audio/ogg"
,
"audio/x-flac+ogg"
,
"audio/x-ogg"
,
NULL
};
...
...
@@ -814,7 +816,11 @@ const struct decoder_plugin oggflac_decoder_plugin = {
static
const
char
*
const
flac_suffixes
[]
=
{
"flac"
,
NULL
};
static
const
char
*
const
flac_mime_types
[]
=
{
"audio/x-flac"
,
"application/x-flac"
,
NULL
"application/flac"
,
"application/x-flac"
,
"audio/flac"
,
"audio/x-flac"
,
NULL
};
const
struct
decoder_plugin
flac_decoder_plugin
=
{
...
...
src/decoder/oggflac_plugin.c
View file @
efc885a9
...
...
@@ -351,9 +351,11 @@ fail:
static
const
char
*
const
oggflac_suffixes
[]
=
{
"ogg"
,
"oga"
,
NULL
};
static
const
char
*
const
oggflac_mime_types
[]
=
{
"audio/x-flac+ogg"
,
"application/ogg"
,
"application/x-ogg"
,
"audio/ogg"
,
"audio/x-ogg"
,
"audio/x-flac+ogg"
,
NULL
};
...
...
src/decoder/vorbis_plugin.c
View file @
efc885a9
...
...
@@ -420,8 +420,13 @@ static const char *const vorbis_suffixes[] = {
static
const
char
*
const
vorbis_mime_types
[]
=
{
"application/ogg"
,
"audio/x-vorbis+ogg"
,
"application/x-ogg"
,
"audio/ogg"
,
"audio/vorbis"
,
"audio/vorbis+ogg"
,
"audio/x-ogg"
,
"audio/x-vorbis"
,
"audio/x-vorbis+ogg"
,
NULL
};
...
...
src/input/curl_input_plugin.c
View file @
efc885a9
...
...
@@ -42,9 +42,6 @@
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "input_curl"
/** rewinding is possible after up to 64 kB */
static
const
goffset
max_rewind_size
=
64
*
1024
;
/**
* Buffers created by input_curl_writefunction().
*/
...
...
@@ -79,9 +76,6 @@ struct input_curl {
/** did libcurl tell us the we're at the end of the response body? */
bool
eof
;
/** limited list of old buffers, for rewinding */
GQueue
*
rewind
;
/** error message provided by libcurl */
char
error
[
CURL_ERROR_SIZE
];
...
...
@@ -179,11 +173,6 @@ input_curl_easy_free(struct input_curl *c)
g_queue_foreach
(
c
->
buffers
,
buffer_free_callback
,
NULL
);
g_queue_clear
(
c
->
buffers
);
if
(
c
->
rewind
!=
NULL
)
{
g_queue_foreach
(
c
->
rewind
,
buffer_free_callback
,
NULL
);
g_queue_clear
(
c
->
rewind
);
}
}
/**
...
...
@@ -204,8 +193,6 @@ input_curl_free(struct input_stream *is)
curl_multi_cleanup
(
c
->
multi
);
g_queue_free
(
c
->
buffers
);
if
(
c
->
rewind
!=
NULL
)
g_queue_free
(
c
->
rewind
);
g_free
(
c
->
url
);
g_free
(
c
);
...
...
@@ -330,7 +317,7 @@ fill_buffer(struct input_stream *is, GError **error_r)
* Mark a part of the buffer object as consumed.
*/
static
struct
buffer
*
consume_buffer
(
struct
buffer
*
buffer
,
size_t
length
,
GQueue
*
rewind_buffers
)
consume_buffer
(
struct
buffer
*
buffer
,
size_t
length
)
{
assert
(
buffer
!=
NULL
);
assert
(
buffer
->
consumed
<
buffer
->
size
);
...
...
@@ -341,10 +328,6 @@ consume_buffer(struct buffer *buffer, size_t length, GQueue *rewind_buffers)
assert
(
buffer
->
consumed
==
buffer
->
size
);
if
(
rewind_buffers
!=
NULL
)
/* append this buffer to the rewind buffer list */
g_queue_push_tail
(
rewind_buffers
,
buffer
);
else
g_free
(
buffer
);
return
NULL
;
...
...
@@ -352,8 +335,7 @@ consume_buffer(struct buffer *buffer, size_t length, GQueue *rewind_buffers)
static
size_t
read_from_buffer
(
struct
icy_metadata
*
icy_metadata
,
GQueue
*
buffers
,
void
*
dest0
,
size_t
length
,
GQueue
*
rewind_buffers
)
void
*
dest0
,
size_t
length
)
{
struct
buffer
*
buffer
=
g_queue_pop_head
(
buffers
);
uint8_t
*
dest
=
dest0
;
...
...
@@ -372,7 +354,7 @@ read_from_buffer(struct icy_metadata *icy_metadata, GQueue *buffers,
if
(
chunk
>
0
)
{
memcpy
(
dest
,
buffer
->
data
+
buffer
->
consumed
,
chunk
);
buffer
=
consume_buffer
(
buffer
,
chunk
,
rewind_buffers
);
buffer
=
consume_buffer
(
buffer
,
chunk
);
nbytes
+=
chunk
;
dest
+=
chunk
;
...
...
@@ -387,7 +369,7 @@ read_from_buffer(struct icy_metadata *icy_metadata, GQueue *buffers,
chunk
=
icy_meta
(
icy_metadata
,
buffer
->
data
+
buffer
->
consumed
,
length
);
if
(
chunk
>
0
)
{
buffer
=
consume_buffer
(
buffer
,
chunk
,
rewind_buffers
);
buffer
=
consume_buffer
(
buffer
,
chunk
);
length
-=
chunk
;
...
...
@@ -427,31 +409,9 @@ input_curl_read(struct input_stream *is, void *ptr, size_t size,
{
struct
input_curl
*
c
=
is
->
data
;
bool
success
;
GQueue
*
rewind_buffers
;
size_t
nbytes
=
0
;
char
*
dest
=
ptr
;
#ifndef NDEBUG
if
(
c
->
rewind
!=
NULL
&&
(
!
g_queue_is_empty
(
c
->
rewind
)
||
is
->
offset
==
0
))
{
goffset
offset
=
0
;
struct
buffer
*
buffer
;
for
(
GList
*
list
=
g_queue_peek_head_link
(
c
->
rewind
);
list
!=
NULL
;
list
=
g_list_next
(
list
))
{
buffer
=
list
->
data
;
offset
+=
buffer
->
consumed
;
assert
(
offset
<=
is
->
offset
);
}
buffer
=
g_queue_peek_head
(
c
->
buffers
);
if
(
buffer
!=
NULL
)
offset
+=
buffer
->
consumed
;
assert
(
offset
==
is
->
offset
);
}
#endif
do
{
/* fill the buffer */
...
...
@@ -461,19 +421,9 @@ input_curl_read(struct input_stream *is, void *ptr, size_t size,
/* send buffer contents */
if
(
c
->
rewind
!=
NULL
&&
(
!
g_queue_is_empty
(
c
->
rewind
)
||
is
->
offset
==
0
))
/* at the beginning or already writing the rewind
buffer list */
rewind_buffers
=
c
->
rewind
;
else
/* we don't need the rewind buffers anymore */
rewind_buffers
=
NULL
;
while
(
size
>
0
&&
!
g_queue_is_empty
(
c
->
buffers
))
{
size_t
copy
=
read_from_buffer
(
&
c
->
icy_metadata
,
c
->
buffers
,
dest
+
nbytes
,
size
,
rewind_buffers
);
dest
+
nbytes
,
size
);
nbytes
+=
copy
;
size
-=
copy
;
...
...
@@ -485,33 +435,6 @@ input_curl_read(struct input_stream *is, void *ptr, size_t size,
is
->
offset
+=
(
goffset
)
nbytes
;
#ifndef NDEBUG
if
(
rewind_buffers
!=
NULL
)
{
goffset
offset
=
0
;
struct
buffer
*
buffer
;
for
(
GList
*
list
=
g_queue_peek_head_link
(
c
->
rewind
);
list
!=
NULL
;
list
=
g_list_next
(
list
))
{
buffer
=
list
->
data
;
offset
+=
buffer
->
consumed
;
assert
(
offset
<=
is
->
offset
);
}
buffer
=
g_queue_peek_head
(
c
->
buffers
);
if
(
buffer
!=
NULL
)
offset
+=
buffer
->
consumed
;
assert
(
offset
==
is
->
offset
);
}
#endif
if
(
rewind_buffers
!=
NULL
&&
is
->
offset
>
max_rewind_size
)
{
/* drop the rewind buffer, it has grown too large */
g_queue_foreach
(
c
->
rewind
,
buffer_free_callback
,
NULL
);
g_queue_clear
(
c
->
rewind
);
}
return
nbytes
;
}
...
...
@@ -646,15 +569,6 @@ input_curl_headerfunction(void *ptr, size_t size, size_t nmemb, void *stream)
/* a stream with icy-metadata is not
seekable */
is
->
seekable
=
false
;
if
(
c
->
rewind
!=
NULL
)
{
/* rewinding with icy-metadata is too
hairy for me .. */
assert
(
g_queue_is_empty
(
c
->
rewind
));
g_queue_free
(
c
->
rewind
);
c
->
rewind
=
NULL
;
}
}
}
...
...
@@ -752,6 +666,18 @@ input_curl_easy_init(struct input_stream *is, GError **error_r)
return
true
;
}
void
input_curl_reinit
(
struct
input_stream
*
is
)
{
struct
input_curl
*
c
=
is
->
data
;
assert
(
is
->
plugin
==
&
input_plugin_curl
);
assert
(
c
->
easy
!=
NULL
);
curl_easy_setopt
(
c
->
easy
,
CURLOPT_WRITEHEADER
,
is
);
curl_easy_setopt
(
c
->
easy
,
CURLOPT_WRITEDATA
,
is
);
}
static
bool
input_curl_send_request
(
struct
input_curl
*
c
,
GError
**
error_r
)
{
...
...
@@ -773,72 +699,6 @@ input_curl_send_request(struct input_curl *c, GError **error_r)
}
static
bool
input_curl_can_rewind
(
struct
input_stream
*
is
)
{
struct
input_curl
*
c
=
is
->
data
;
struct
buffer
*
buffer
;
if
(
c
->
rewind
==
NULL
)
return
false
;
if
(
!
g_queue_is_empty
(
c
->
rewind
))
/* the rewind buffer hasn't been wiped yet */
return
true
;
if
(
g_queue_is_empty
(
c
->
buffers
))
/* there are no buffers at all - cheap rewind not
possible */
return
false
;
/* rewind is possible if this is the very first buffer of the
resource */
buffer
=
(
struct
buffer
*
)
g_queue_peek_head
(
c
->
buffers
);
return
(
goffset
)
buffer
->
consumed
==
is
->
offset
;
}
static
void
input_curl_rewind
(
struct
input_stream
*
is
)
{
struct
input_curl
*
c
=
is
->
data
;
#ifndef NDEBUG
goffset
offset
=
0
;
#endif
assert
(
c
->
rewind
!=
NULL
);
/* rewind the current buffer */
if
(
!
g_queue_is_empty
(
c
->
buffers
))
{
struct
buffer
*
buffer
=
(
struct
buffer
*
)
g_queue_peek_head
(
c
->
buffers
);
#ifndef NDEBUG
offset
+=
buffer
->
consumed
;
#endif
buffer
->
consumed
=
0
;
}
/* reset and move all rewind buffers back to the regular buffer list */
while
(
!
g_queue_is_empty
(
c
->
rewind
))
{
struct
buffer
*
buffer
=
(
struct
buffer
*
)
g_queue_pop_tail
(
c
->
rewind
);
#ifndef NDEBUG
offset
+=
buffer
->
consumed
;
#endif
buffer
->
consumed
=
0
;
g_queue_push_head
(
c
->
buffers
,
buffer
);
}
assert
(
offset
==
is
->
offset
);
is
->
offset
=
0
;
/* rewind the icy_metadata object */
icy_reset
(
&
c
->
icy_metadata
);
}
static
bool
input_curl_seek
(
struct
input_stream
*
is
,
goffset
offset
,
int
whence
,
GError
**
error_r
)
{
...
...
@@ -847,18 +707,10 @@ input_curl_seek(struct input_stream *is, goffset offset, int whence,
assert
(
is
->
ready
);
if
(
whence
==
SEEK_SET
&&
offset
==
0
)
{
if
(
is
->
offset
==
0
)
if
(
whence
==
SEEK_SET
&&
offset
==
is
->
offset
)
/* no-op */
return
true
;
if
(
input_curl_can_rewind
(
is
))
{
/* we have enough rewind buffers left */
input_curl_rewind
(
is
);
return
true
;
}
}
if
(
!
is
->
seekable
)
return
false
;
...
...
@@ -890,26 +742,16 @@ input_curl_seek(struct input_stream *is, goffset offset, int whence,
/* check if we can fast-forward the buffer */
while
(
offset
>
is
->
offset
&&
!
g_queue_is_empty
(
c
->
buffers
))
{
GQueue
*
rewind_buffers
;
struct
buffer
*
buffer
;
size_t
length
;
if
(
c
->
rewind
!=
NULL
&&
(
!
g_queue_is_empty
(
c
->
rewind
)
||
is
->
offset
==
0
))
/* at the beginning or already writing the rewind
buffer list */
rewind_buffers
=
c
->
rewind
;
else
/* we don't need the rewind buffers anymore */
rewind_buffers
=
NULL
;
buffer
=
(
struct
buffer
*
)
g_queue_pop_head
(
c
->
buffers
);
length
=
buffer
->
size
-
buffer
->
consumed
;
if
(
offset
-
is
->
offset
<
(
goffset
)
length
)
length
=
offset
-
is
->
offset
;
buffer
=
consume_buffer
(
buffer
,
length
,
rewind_buffers
);
buffer
=
consume_buffer
(
buffer
,
length
);
if
(
buffer
!=
NULL
)
g_queue_push_head
(
c
->
buffers
,
buffer
);
...
...
@@ -962,7 +804,6 @@ input_curl_open(struct input_stream *is, const char *url, GError **error_r)
c
=
g_new0
(
struct
input_curl
,
1
);
c
->
url
=
g_strdup
(
url
);
c
->
buffers
=
g_queue_new
();
c
->
rewind
=
g_queue_new
();
is
->
plugin
=
&
input_plugin_curl
;
is
->
data
=
c
;
...
...
src/input/curl_input_plugin.h
View file @
efc885a9
...
...
@@ -20,6 +20,16 @@
#ifndef MPD_INPUT_CURL_H
#define MPD_INPUT_CURL_H
struct
input_stream
;
extern
const
struct
input_plugin
input_plugin_curl
;
/**
* This is a workaround for an input_stream API deficiency; after
* exchanging the input_stream pointer in input_rewind_open(), this
* function is called to reinitialize CURL's data pointers.
*/
void
input_curl_reinit
(
struct
input_stream
*
is
);
#endif
src/input/rewind_input_plugin.c
0 → 100644
View file @
efc885a9
/*
* Copyright (C) 2003-2009 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include "input/rewind_input_plugin.h"
#include "input/curl_input_plugin.h"
#include "input_plugin.h"
#include "tag.h"
#include <glib.h>
#include <assert.h>
#include <stdio.h>
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "input_rewind"
struct
input_rewind
{
struct
input_stream
input
;
/**
* The read position within the buffer. Undefined as long as
* reading_from_buffer() returns false.
*/
size_t
head
;
/**
* The write/append position within the buffer.
*/
size_t
tail
;
/**
* The size of this buffer is the maximum number of bytes
* which can be rewinded cheaply without passing the "seek"
* call to CURL.
*
* The origin of this buffer is always the beginning of the
* stream (offset 0).
*/
char
buffer
[
64
*
1024
];
};
/**
* Are we currently reading from the buffer, and does the buffer
* contain more data for the next read operation?
*/
static
bool
reading_from_buffer
(
const
struct
input_stream
*
is
)
{
const
struct
input_rewind
*
r
=
is
->
data
;
return
r
->
tail
>
0
&&
is
->
offset
<
r
->
input
.
offset
;
}
/**
* Copy public attributes from the underlying input stream to the
* "rewind" input stream. This function is called when a method of
* the underlying stream has returned, which may have modified these
* attributes.
*/
static
void
copy_attributes
(
struct
input_stream
*
dest
)
{
const
struct
input_rewind
*
r
=
dest
->
data
;
const
struct
input_stream
*
src
=
&
r
->
input
;
dest
->
ready
=
src
->
ready
;
dest
->
seekable
=
src
->
seekable
;
dest
->
size
=
src
->
size
;
dest
->
offset
=
src
->
offset
;
if
(
dest
->
mime
==
NULL
&&
src
->
mime
!=
NULL
)
/* this is set only once, and the duplicated pointer
is freed by input_stream_close() */
dest
->
mime
=
g_strdup
(
src
->
mime
);
}
static
void
input_rewind_close
(
struct
input_stream
*
is
)
{
struct
input_rewind
*
r
=
is
->
data
;
input_stream_close
(
&
r
->
input
);
g_free
(
r
);
}
static
struct
tag
*
input_rewind_tag
(
struct
input_stream
*
is
)
{
struct
input_rewind
*
r
=
is
->
data
;
return
input_stream_tag
(
&
r
->
input
);
}
static
int
input_rewind_buffer
(
struct
input_stream
*
is
,
GError
**
error_r
)
{
struct
input_rewind
*
r
=
is
->
data
;
int
ret
=
input_stream_buffer
(
&
r
->
input
,
error_r
);
if
(
ret
<
0
||
!
reading_from_buffer
(
is
))
copy_attributes
(
is
);
return
ret
;
}
static
size_t
input_rewind_read
(
struct
input_stream
*
is
,
void
*
ptr
,
size_t
size
,
GError
**
error_r
)
{
struct
input_rewind
*
r
=
is
->
data
;
if
(
reading_from_buffer
(
is
))
{
/* buffered read */
assert
(
r
->
head
==
(
size_t
)
is
->
offset
);
assert
(
r
->
tail
==
(
size_t
)
r
->
input
.
offset
);
if
(
size
>
r
->
tail
-
r
->
head
)
size
=
r
->
tail
-
r
->
head
;
memcpy
(
ptr
,
r
->
buffer
+
r
->
head
,
size
);
r
->
head
+=
size
;
is
->
offset
+=
size
;
return
size
;
}
else
{
/* pass method call to underlying stream */
size_t
nbytes
=
input_stream_read
(
&
r
->
input
,
ptr
,
size
,
error_r
);
if
(
r
->
input
.
offset
>
(
goffset
)
sizeof
(
r
->
buffer
))
/* disable buffering */
r
->
tail
=
0
;
else
if
(
r
->
tail
==
(
size_t
)
is
->
offset
)
{
/* append to buffer */
memcpy
(
r
->
buffer
+
r
->
tail
,
ptr
,
nbytes
);
r
->
tail
+=
nbytes
;
assert
(
r
->
tail
==
(
size_t
)
r
->
input
.
offset
);
}
copy_attributes
(
is
);
return
nbytes
;
}
}
static
bool
input_rewind_eof
(
G_GNUC_UNUSED
struct
input_stream
*
is
)
{
struct
input_rewind
*
r
=
is
->
data
;
return
!
reading_from_buffer
(
is
)
&&
input_stream_eof
(
&
r
->
input
);
}
static
bool
input_rewind_seek
(
struct
input_stream
*
is
,
goffset
offset
,
int
whence
,
GError
**
error_r
)
{
struct
input_rewind
*
r
=
is
->
data
;
assert
(
is
->
ready
);
if
(
whence
==
SEEK_SET
&&
r
->
tail
>
0
&&
offset
<=
(
goffset
)
r
->
tail
)
{
/* buffered seek */
assert
(
!
reading_from_buffer
(
is
)
||
r
->
head
==
(
size_t
)
is
->
offset
);
assert
(
r
->
tail
==
(
size_t
)
r
->
input
.
offset
);
r
->
head
=
(
size_t
)
offset
;
is
->
offset
=
offset
;
return
true
;
}
else
{
bool
success
=
input_stream_seek
(
&
r
->
input
,
offset
,
whence
,
error_r
);
copy_attributes
(
is
);
/* disable the buffer, because r->input has left the
buffered range now */
r
->
tail
=
0
;
return
success
;
}
}
static
const
struct
input_plugin
rewind_input_plugin
=
{
.
close
=
input_rewind_close
,
.
tag
=
input_rewind_tag
,
.
buffer
=
input_rewind_buffer
,
.
read
=
input_rewind_read
,
.
eof
=
input_rewind_eof
,
.
seek
=
input_rewind_seek
,
};
void
input_rewind_open
(
struct
input_stream
*
is
)
{
struct
input_rewind
*
c
;
assert
(
is
!=
NULL
);
assert
(
is
->
offset
==
0
);
if
(
is
->
plugin
!=
&
input_plugin_curl
)
/* due to limitations in the input_plugin API, we only
(explicitly) support the CURL input plugin */
return
;
c
=
g_new
(
struct
input_rewind
,
1
);
c
->
tail
=
0
;
/* move the CURL input stream to c->input */
c
->
input
=
*
is
;
input_curl_reinit
(
&
c
->
input
);
/* convert the existing input_stream pointer to a "rewind"
input stream */
is
->
plugin
=
&
rewind_input_plugin
;
is
->
data
=
c
;
}
src/input/rewind_input_plugin.h
0 → 100644
View file @
efc885a9
/*
* Copyright (C) 2003-2009 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/** \file
*
* A wrapper for an input_stream object which allows cheap buffered
* rewinding. This is useful while detecting the stream codec (let
* each decoder plugin peek a portion from the stream).
*/
#ifndef MPD_INPUT_REWIND_H
#define MPD_INPUT_REWIND_H
#include "check.h"
struct
input_stream
;
#ifdef ENABLE_CURL
void
input_rewind_open
(
struct
input_stream
*
is
);
#else
static
inline
void
input_rewind_open
(
struct
input_stream
*
is
)
{
(
void
)
is
;
}
#endif
#endif
src/input_stream.c
View file @
efc885a9
...
...
@@ -21,6 +21,7 @@
#include "input_stream.h"
#include "input_registry.h"
#include "input_plugin.h"
#include "input/rewind_input_plugin.h"
#include <glib.h>
#include <assert.h>
...
...
@@ -57,6 +58,8 @@ input_stream_open(struct input_stream *is, const char *url, GError **error_r)
assert
(
is
->
plugin
->
eof
!=
NULL
);
assert
(
!
is
->
seekable
||
is
->
plugin
->
seek
!=
NULL
);
input_rewind_open
(
is
);
return
true
;
}
else
if
(
error
!=
NULL
)
{
g_propagate_error
(
error_r
,
error
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment