2 * Copyright 2007 Kevin Ko <kevin.s.ko@gmail.com>
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21 #include <ffmpeg/avcodec.h>
22 #include <ffmpeg/avformat.h>
23 #include <ffmpeg/avio.h>
30 #define NUM_FFMPEG_KEYS 8
35 uint8_t *curr_pkt_buf
;
38 struct ffmpeg_output
{
40 uint8_t *buffer_pos
; /* current buffer position */
44 struct ffmpeg_private
{
45 AVCodecContext
*codec_context
;
46 AVFormatContext
*input_context
;
49 struct ffmpeg_input
*input
;
50 struct ffmpeg_output
*output
;
53 static struct ffmpeg_input
*ffmpeg_input_create(void)
55 struct ffmpeg_input
*input
= xnew(struct ffmpeg_input
, 1);
57 if (av_new_packet(&input
->pkt
, 0) != 0) {
61 input
->curr_pkt_size
= 0;
62 input
->curr_pkt_buf
= input
->pkt
.data
;
66 static void ffmpeg_input_free(struct ffmpeg_input
*input
)
68 av_free_packet(&input
->pkt
);
71 static struct ffmpeg_output
*ffmpeg_output_create(void)
73 struct ffmpeg_output
*output
= xnew(struct ffmpeg_output
, 1);
75 output
->buffer
= xnew(uint8_t, AVCODEC_MAX_AUDIO_FRAME_SIZE
);
76 output
->buffer_pos
= output
->buffer
;
77 output
->buffer_used_len
= 0;
81 static void ffmpeg_output_free(struct ffmpeg_output
*output
)
84 output
->buffer
= NULL
;
88 static inline void ffmpeg_buffer_flush(struct ffmpeg_output
*output
)
90 output
->buffer_pos
= output
->buffer
;
91 output
->buffer_used_len
= 0;
94 static void ffmpeg_init(void)
96 static int inited
= 0;
102 av_log_set_level(AV_LOG_QUIET
);
104 #if (LIBAVFORMAT_VERSION_INT <= ((50<<16) + (4<<8) + 0))
106 register_avcodec(&wmav1_decoder
);
107 register_avcodec(&wmav2_decoder
);
109 /* libavformat versions <= 50.4.0 have asf_init(). From SVN revision
110 * 5697->5707 of asf.c, this function was removed, preferring the use of
111 * explicit calls. Note that version 50.5.0 coincides with SVN revision
112 * 5729, so there is a window of incompatibility for revisions 5707 and 5720
117 /* Uncomment this for shorten (.shn) support.
118 register_avcodec(&shorten_decoder);
122 register_protocol(&file_protocol
);
124 /* We could register decoders explicitly to save memory, but we have to
125 * be careful about compatibility. */
130 static int ffmpeg_open(struct input_plugin_data
*ip_data
)
132 struct ffmpeg_private
*priv
;
135 int stream_index
= -1;
137 AVCodecContext
*cc
= NULL
;
143 err
= av_open_input_file(&ic
, ip_data
->filename
, NULL
, 0, NULL
);
145 d_print("av_open failed: %d\n", err
);
146 err
= -IP_ERROR_FILE_FORMAT
;
150 err
= av_find_stream_info(ic
);
152 d_print("unable to find stream info: %d\n", err
);
153 err
= -IP_ERROR_FILE_FORMAT
;
157 for (i
= 0; i
< ic
->nb_streams
; i
++) {
158 cc
= ic
->streams
[i
]->codec
;
159 if (cc
->codec_type
== CODEC_TYPE_AUDIO
) {
165 if (stream_index
== -1) {
166 d_print("could not find audio stream\n");
167 err
= -IP_ERROR_FILE_FORMAT
;
171 codec
= avcodec_find_decoder(cc
->codec_id
);
173 d_print("codec not found: %d, %s\n", cc
->codec_id
, cc
->codec_name
);
174 err
= -IP_ERROR_FILE_FORMAT
;
178 if (codec
->capabilities
& CODEC_CAP_TRUNCATED
)
179 cc
->flags
|= CODEC_FLAG_TRUNCATED
;
181 if (avcodec_open(cc
, codec
) < 0) {
182 d_print("could not open codec: %d, %s\n", cc
->codec_id
, cc
->codec_name
);
183 err
= -IP_ERROR_FILE_FORMAT
;
186 /* We assume below that no more errors follow. */
190 /* Clean up. cc is never opened at this point. (See above assumption.) */
191 av_close_input_file(ic
);
195 priv
= xnew(struct ffmpeg_private
, 1);
196 priv
->codec_context
= cc
;
197 priv
->input_context
= ic
;
198 priv
->stream_index
= stream_index
;
199 priv
->input
= ffmpeg_input_create();
200 if (priv
->input
== NULL
) {
202 av_close_input_file(ic
);
204 return -IP_ERROR_INTERNAL
;
206 priv
->output
= ffmpeg_output_create();
208 ip_data
->private = priv
;
209 ip_data
->sf
= sf_rate(cc
->sample_rate
) | sf_channels(cc
->channels
) | sf_bits(16) | sf_signed(1);
213 static int ffmpeg_close(struct input_plugin_data
*ip_data
)
215 struct ffmpeg_private
*priv
= ip_data
->private;
217 avcodec_close(priv
->codec_context
);
218 av_close_input_file(priv
->input_context
);
219 ffmpeg_input_free(priv
->input
);
220 ffmpeg_output_free(priv
->output
);
222 ip_data
->private = NULL
;
227 * This returns the number of bytes added to the buffer.
228 * It returns < 0 on error. 0 on EOF.
230 static int ffmpeg_fill_buffer(AVFormatContext
* ic
, AVCodecContext
* cc
, struct ffmpeg_input
*input
,
231 struct ffmpeg_output
*output
)
233 /* frame_size specifies the size of output->buffer for
234 * avcodec_decode_audio2. */
235 int frame_size
= AVCODEC_MAX_AUDIO_FRAME_SIZE
;
239 if (input
->curr_pkt_size
<= 0) {
240 av_free_packet(&input
->pkt
);
241 if (av_read_frame(ic
, &input
->pkt
) < 0) {
242 /* Force EOF once we can read no longer. */
245 input
->curr_pkt_size
= input
->pkt
.size
;
246 input
->curr_pkt_buf
= input
->pkt
.data
;
250 /* The change to avcodec_decode_audio2 occurred between
251 * 51.28.0 and 51.29.0 */
252 #if (LIBAVCODEC_VERSION_INT <= ((51<<16) + (28<<8) + 0))
253 len
= avcodec_decode_audio(cc
, (int16_t *)output
->buffer
, &frame_size
,
254 input
->curr_pkt_buf
, input
->curr_pkt_size
);
256 len
= avcodec_decode_audio2(cc
, (int16_t *) output
->buffer
, &frame_size
,
257 input
->curr_pkt_buf
, input
->curr_pkt_size
);
259 input
->curr_pkt_size
-= len
;
260 input
->curr_pkt_buf
+= len
;
261 if (frame_size
> 0) {
262 output
->buffer_pos
= output
->buffer
;
263 output
->buffer_used_len
= frame_size
;
267 /* This should never get here. */
268 return -IP_ERROR_INTERNAL
;
271 static int ffmpeg_read(struct input_plugin_data
*ip_data
, char *buffer
, int count
)
273 struct ffmpeg_private
*priv
= ip_data
->private;
274 struct ffmpeg_output
*output
= priv
->output
;
278 if (output
->buffer_used_len
== 0) {
279 rc
= ffmpeg_fill_buffer(priv
->input_context
, priv
->codec_context
, priv
->input
, priv
->output
);
284 out_size
= min(output
->buffer_used_len
, count
);
285 memcpy(buffer
, output
->buffer_pos
, out_size
);
286 output
->buffer_used_len
-= out_size
;
287 output
->buffer_pos
+= out_size
;
291 static int ffmpeg_seek(struct input_plugin_data
*ip_data
, double offset
)
293 struct ffmpeg_private
*priv
= ip_data
->private;
294 AVStream
*st
= priv
->input_context
->streams
[priv
->stream_index
];
297 /* There is a bug that was fixed in ffmpeg revision 5099 that affects seeking.
298 * Apparently, the stream's timebase was not used consistently in asf.c.
299 * Prior to 5099, ASF seeking assumed seconds as inputs. There is a
300 * window of incompatibility, since avformat's version was not updated at
301 * the same time. Instead, the transition to 50.3.0 occurred at
303 #if (LIBAVFORMAT_VERSION_INT < ((50<<16)+(3<<8)+0))
304 int64_t pts
= (int64_t) offset
;
306 /* time base is 1/framerate */
307 int64_t pts
= (int64_t) offset
* st
->time_base
.den
;
310 ret
= av_seek_frame(priv
->input_context
, priv
->stream_index
, pts
, 0);
313 return -IP_ERROR_FUNCTION_NOT_SUPPORTED
;
315 ffmpeg_buffer_flush(priv
->output
);
321 static int set_comment(struct keyval
*comment
, int i
, const char *key
, const char *val
)
326 comment
[i
].key
= xstrdup(key
);
327 comment
[i
].val
= xstrdup(val
);
331 static int ffmpeg_read_comments(struct input_plugin_data
*ip_data
, struct keyval
**comments
)
334 struct ffmpeg_private
*priv
= ip_data
->private;
335 AVFormatContext
*ic
= priv
->input_context
;
338 *comments
= xnew0(struct keyval
, NUM_FFMPEG_KEYS
+ 1);
340 i
= set_comment(*comments
, i
, "artist", ic
->author
);
341 i
= set_comment(*comments
, i
, "album", ic
->album
);
342 i
= set_comment(*comments
, i
, "title", ic
->title
);
343 i
= set_comment(*comments
, i
, "genre", ic
->genre
);
346 snprintf(buff
, sizeof(buff
), "%d", ic
->year
);
347 i
= set_comment(*comments
, i
, "date", buff
);
350 if (ic
->track
!= 0) {
351 snprintf(buff
, sizeof(buff
), "%d", ic
->track
);
352 i
= set_comment(*comments
, i
, "tracknumber", buff
);
358 static int ffmpeg_duration(struct input_plugin_data
*ip_data
)
360 struct ffmpeg_private
*priv
= ip_data
->private;
361 return priv
->input_context
->duration
/ 1000000L;
364 const struct input_plugin_ops ip_ops
= {
366 .close
= ffmpeg_close
,
369 .read_comments
= ffmpeg_read_comments
,
370 .duration
= ffmpeg_duration
373 const char *const ip_extensions
[] = { "wma", NULL
};
374 const char *const ip_mime_types
[] = { NULL
};