1 | | Index: THANKS |
2 | | =================================================================== |
3 | | --- THANKS (revision 2506) |
4 | | +++ THANKS (revision 2529) |
5 | | @@ -10,6 +10,9 @@ |
6 | | * Fixed miscellaneous coding errors. |
7 | | * Assisted with testing. |
8 | | |
9 | | +Gregory Maxwell: |
10 | | + * Provided patch for off_t in io_* functions. |
11 | | + |
12 | | Morten Grunnet Buhl: |
13 | | * Provided Yellow/Red theme. |
14 | | |
15 | | @@ -44,6 +47,7 @@ |
16 | | * Headed the effort to port MOC to OpenWRT. |
17 | | * Provided signficant information on DTS, AAC and other formats. |
18 | | * Also contributed much time in the refinement of feature ideas. |
19 | | + * Provided 24-bit format conversion bug fixes. |
20 | | |
21 | | Juho Hämäläinen: |
22 | | * Added -Q (--format) FORMAT_STRING option to display file information. |
23 | | @@ -202,6 +206,9 @@ |
24 | | * Fixed segfault when trying to play a file using FFmpeg. |
25 | | * Migrated to newer FFmpeg API. |
26 | | |
27 | | +"firejox" |
28 | | + * Fixed screen upsets due to UTF-8 character handing. |
29 | | + |
30 | | "fluxid": |
31 | | * Fixed incorrect setting for themes red channel value. |
32 | | |
33 | | Index: mocp.1 |
34 | | =================================================================== |
35 | | --- mocp.1 (revision 2506) |
36 | | +++ mocp.1 (revision 2529) |
37 | | @@ -69,6 +69,11 @@ |
38 | | set in the configuration file as \fBStartInMusicDir\fP. |
39 | | .LP |
40 | | .TP |
41 | | +\fB\-q\fP, \fB\-\-enqueue\fP |
42 | | +Add files given after command line options to the queue. Don't start the |
43 | | +interface. |
44 | | +.LP |
45 | | +.TP |
46 | | \fB\-a\fP, \fB\-\-append\fP |
47 | | Append files, directories (recursively) and playlists given after command |
48 | | line options to the playlist. Don't start the interface. |
49 | | Index: menu.c |
50 | | =================================================================== |
51 | | --- menu.c (revision 2506) |
52 | | +++ menu.c (revision 2529) |
53 | | @@ -90,9 +90,14 @@ |
54 | | getyx (menu->win, y, x); |
55 | | if (title_width <= title_space || mi->align == MENU_ALIGN_LEFT) |
56 | | xwaddnstr (menu->win, mi->title, title_space); |
57 | | - else |
58 | | - xwaddstr (menu->win, mi->title + title_width - title_space); |
59 | | + else { |
60 | | + char *ptr; |
61 | | |
62 | | + ptr = xstrtail (mi->title, title_space); |
63 | | + xwaddstr (menu->win, ptr); |
64 | | + free (ptr); |
65 | | + } |
66 | | + |
67 | | /* Fill the remainder of the title field with spaces. */ |
68 | | if (mi == menu->selected) { |
69 | | getyx (menu->win, y, ix); |
70 | | Index: configure.in |
71 | | =================================================================== |
72 | | --- configure.in (revision 2506) |
73 | | +++ configure.in (revision 2529) |
74 | | @@ -142,7 +142,7 @@ |
75 | | |
76 | | PKG_PROG_PKG_CONFIG([0.20]) |
77 | | |
78 | | -if test "x$PKG_CONFIG" == "x" |
79 | | +if test "x$PKG_CONFIG" = "x" |
80 | | then |
81 | | AC_MSG_WARN([No pkg-config utility found or it's too old, I will have trouble finding installed libraries.]) |
82 | | fi |
83 | | @@ -293,7 +293,6 @@ |
84 | | |
85 | | dnl optional functions |
86 | | AC_CHECK_FUNCS([strcasestr strerror_r syslog]) |
87 | | -AC_CHECK_FUNCS([getrlimit pthread_attr_getstacksize]) |
88 | | AX_CHECK_UNAME_SYSCALL |
89 | | |
90 | | dnl MIME magic |
91 | | @@ -322,6 +321,7 @@ |
92 | | CC="$PTHREAD_CC" |
93 | | CFLAGS="$PTHREAD_CFLAGS $CFLAGS" |
94 | | EXTRA_LIBS="$EXTRA_LIBS $PTHREAD_LIBS" |
95 | | +AC_CHECK_FUNCS([getrlimit pthread_attr_getstacksize]) |
96 | | |
97 | | dnl __FUNCTION__ |
98 | | AC_TRY_COMPILE(,[printf(__FUNCTION__);], [AC_DEFINE([HAVE__FUNCTION__], 1, |
99 | | @@ -342,7 +342,7 @@ |
100 | | fi |
101 | | |
102 | | dnl popt |
103 | | -AC_SEARCH_LIBS([poptGetContext], [popt], , [POPT_MISSING="yes"]) |
104 | | +AC_CHECK_LIB([popt], [poptGetContext], [true], [POPT_MISSING="yes"]) |
105 | | |
106 | | dnl getopt |
107 | | AC_CHECK_FUNC(getopt_long, |
108 | | Index: utf8.c |
109 | | =================================================================== |
110 | | --- utf8.c (revision 2506) |
111 | | +++ utf8.c (revision 2529) |
112 | | @@ -199,47 +199,50 @@ |
113 | | |
114 | | int xwaddnstr (WINDOW *win, const char *str, const int n) |
115 | | { |
116 | | - int res; |
117 | | + int res, width, inv_char; |
118 | | + wchar_t *ucs; |
119 | | + char *mstr, *lstr; |
120 | | + size_t size, num_chars; |
121 | | |
122 | | assert (n > 0); |
123 | | assert (str != NULL); |
124 | | |
125 | | - if (using_utf8) { |
126 | | + mstr = iconv_str (iconv_desc, str); |
127 | | |
128 | | - /* This nasty hack is because we need to count n in chars, but |
129 | | - * [w]addnstr() takes arguments in bytes (in UTF-8 a char can be |
130 | | - * longer than 1 byte). There are also problems with [w]addnwstr() |
131 | | - * (screen garbled). I have no better idea. */ |
132 | | + size = xmbstowcs (NULL, mstr, -1, NULL) + 1; |
133 | | + ucs = (wchar_t *)xmalloc (sizeof(wchar_t) * size); |
134 | | + xmbstowcs (ucs, mstr, size, &inv_char); |
135 | | + width = wcswidth (ucs, WIDTH_MAX); |
136 | | |
137 | | - wchar_t *ucs; |
138 | | - size_t size; |
139 | | - size_t utf_num_chars; |
140 | | - int inv_char; |
141 | | - |
142 | | - size = xmbstowcs (NULL, str, -1, NULL) + 1; |
143 | | - ucs = (wchar_t *)xmalloc (sizeof(wchar_t) * size); |
144 | | - xmbstowcs (ucs, str, size, &inv_char); |
145 | | - if ((size_t)n < size - 1) |
146 | | - ucs[n] = L'\0'; |
147 | | - utf_num_chars = wcstombs (NULL, ucs, 0); |
148 | | - if (inv_char) { |
149 | | - char *utf8 = (char *)xmalloc (utf_num_chars + 1); |
150 | | - |
151 | | - wcstombs (utf8, ucs, utf_num_chars + 1); |
152 | | - res = waddstr (win, utf8); |
153 | | - free (utf8); |
154 | | + if (width == -1) { |
155 | | + size_t clidx; |
156 | | + for (clidx = 0; clidx < size - 1; clidx++) { |
157 | | + if (wcwidth (ucs[clidx]) == -1) |
158 | | + ucs[clidx] = L'?'; |
159 | | } |
160 | | - else |
161 | | - res = waddnstr (win, str, utf_num_chars); |
162 | | - free (ucs); |
163 | | + width = wcswidth (ucs, WIDTH_MAX); |
164 | | + inv_char = 1; |
165 | | } |
166 | | - else { |
167 | | - char *lstr = iconv_str (iconv_desc, str); |
168 | | |
169 | | - res = waddnstr (win, lstr, n); |
170 | | - free (lstr); |
171 | | + if (width > n) { |
172 | | + while (width > n) |
173 | | + width -= wcwidth (ucs[--size]); |
174 | | + ucs[size] = L'\0'; |
175 | | } |
176 | | |
177 | | + num_chars = wcstombs (NULL, ucs, 0); |
178 | | + lstr = (char *)xmalloc (num_chars + 1); |
179 | | + |
180 | | + if (inv_char) |
181 | | + wcstombs (lstr, ucs, num_chars + 1); |
182 | | + else |
183 | | + snprintf (lstr, num_chars + 1, "%s", mstr); |
184 | | + |
185 | | + res = waddstr (win, lstr); |
186 | | + |
187 | | + free (ucs); |
188 | | + free (lstr); |
189 | | + free (mstr); |
190 | | return res; |
191 | | } |
192 | | |
193 | | Index: audio_conversion.c |
194 | | =================================================================== |
195 | | --- audio_conversion.c (revision 2506) |
196 | | +++ audio_conversion.c (revision 2529) |
197 | | @@ -189,7 +189,7 @@ |
198 | | size_t i; |
199 | | |
200 | | /* maximum and minimum values of 32-bit samples */ |
201 | | - const unsigned int U32_MAX = (1 << 24); |
202 | | + const unsigned int U32_MAX = (1 << 24) - 1; |
203 | | const int S32_MAX = (1 << 23) - 1; |
204 | | const int S32_MIN = -(1 << 23); |
205 | | |
206 | | @@ -201,7 +201,7 @@ |
207 | | float f = in[i] * S32_MAX; |
208 | | |
209 | | if (f >= S32_MAX) |
210 | | - *out_val = U32_MAX; |
211 | | + *out_val = U32_MAX << 8; |
212 | | else if (f <= S32_MIN) |
213 | | *out_val = 0; |
214 | | else { |
215 | | @@ -231,9 +231,9 @@ |
216 | | float f = in[i] * S32_MAX; |
217 | | |
218 | | if (f >= S32_MAX) |
219 | | - *out_val = S32_MAX; |
220 | | + *out_val = S32_MAX << 8; |
221 | | else if (f <= S32_MIN) |
222 | | - *out_val = S32_MIN; |
223 | | + *out_val = S32_MIN << 8; |
224 | | else { |
225 | | #ifdef HAVE_LRINTF |
226 | | *out_val = lrintf(f) << 8; |
227 | | Index: io.c |
228 | | =================================================================== |
229 | | --- io.c (revision 2506) |
230 | | +++ io.c (revision 2529) |
231 | | @@ -141,20 +141,20 @@ |
232 | | } |
233 | | |
234 | | #ifdef HAVE_MMAP |
235 | | -static off_t io_seek_mmap (struct io_stream *s, const long where) |
236 | | +static off_t io_seek_mmap (struct io_stream *s, const off_t where) |
237 | | { |
238 | | - assert (RANGE(0, where, (long)s->size)); |
239 | | + assert (RANGE(0, where, (off_t)s->size)); |
240 | | |
241 | | return (s->mem_pos = where); |
242 | | } |
243 | | #endif |
244 | | |
245 | | -static off_t io_seek_fd (struct io_stream *s, const int where) |
246 | | +static off_t io_seek_fd (struct io_stream *s, const off_t where) |
247 | | { |
248 | | return lseek (s->fd, where, SEEK_SET); |
249 | | } |
250 | | |
251 | | -static off_t io_seek_buffered (struct io_stream *s, const long where) |
252 | | +static off_t io_seek_buffered (struct io_stream *s, const off_t where) |
253 | | { |
254 | | off_t res = -1; |
255 | | |
256 | | @@ -180,7 +180,7 @@ |
257 | | return res; |
258 | | } |
259 | | |
260 | | -static off_t io_seek_unbuffered (struct io_stream *s, const long where) |
261 | | +static off_t io_seek_unbuffered (struct io_stream *s, const off_t where) |
262 | | { |
263 | | off_t res = -1; |
264 | | |
265 | | Index: decoder_plugins/mp3/mp3.c |
266 | | =================================================================== |
267 | | --- decoder_plugins/mp3/mp3.c (revision 2506) |
268 | | +++ decoder_plugins/mp3/mp3.c (revision 2529) |
269 | | @@ -696,17 +696,19 @@ |
270 | | { |
271 | | char *ext; |
272 | | |
273 | | + strcpy (buf, "MPx"); |
274 | | + |
275 | | ext = ext_pos (file); |
276 | | - if (!strcasecmp (ext, "mp3")) |
277 | | - strcpy (buf, "MP3"); |
278 | | - else if (!strcasecmp (ext, "mp2")) |
279 | | - strcpy (buf, "MP2"); |
280 | | - else if (!strcasecmp (ext, "mp1")) |
281 | | - strcpy (buf, "MP1"); |
282 | | - else if (!strcasecmp (ext, "mpga")) |
283 | | - strcpy (buf, "MPG"); |
284 | | - else |
285 | | - strcpy (buf, "MPx"); |
286 | | + if (ext) { |
287 | | + if (!strcasecmp (ext, "mp3")) |
288 | | + strcpy (buf, "MP3"); |
289 | | + else if (!strcasecmp (ext, "mp2")) |
290 | | + strcpy (buf, "MP2"); |
291 | | + else if (!strcasecmp (ext, "mp1")) |
292 | | + strcpy (buf, "MP1"); |
293 | | + else if (!strcasecmp (ext, "mpga")) |
294 | | + strcpy (buf, "MPG"); |
295 | | + } |
296 | | } |
297 | | |
298 | | static int mp3_our_format_ext (const char *ext) |
299 | | Index: decoder_plugins/ffmpeg/ffmpeg.m4 |
300 | | =================================================================== |
301 | | --- decoder_plugins/ffmpeg/ffmpeg.m4 (revision 2506) |
302 | | +++ decoder_plugins/ffmpeg/ffmpeg.m4 (revision 2529) |
303 | | @@ -88,6 +88,27 @@ |
304 | | [#include <libavcodec/avcodec.h>]) |
305 | | AC_CHECK_DECLS([AV_CODEC_ID_OPUS], , , |
306 | | [#include <libavcodec/avcodec.h>]) |
307 | | + AC_SEARCH_LIBS(avcodec_free_frame, avcodec, |
308 | | + [AC_DEFINE([HAVE_AVCODEC_FREE_FRAME], 1, |
309 | | + [Define to 1 if you have the `avcodec_free_frame' function.])]) |
310 | | + AC_CHECK_DECLS([CODEC_ID_PCM_S8_PLANAR], , , |
311 | | + [#include <libavcodec/avcodec.h>]) |
312 | | + AC_CHECK_DECLS([AV_SAMPLE_FMT_U8P], , , |
313 | | + [#include <libavcodec/avcodec.h>]) |
314 | | + AC_CHECK_DECLS([AV_SAMPLE_FMT_S16P], , , |
315 | | + [#include <libavcodec/avcodec.h>]) |
316 | | + AC_CHECK_DECLS([AV_SAMPLE_FMT_S32P], , , |
317 | | + [#include <libavcodec/avcodec.h>]) |
318 | | + AC_CHECK_DECLS([AV_SAMPLE_FMT_FLTP], , , |
319 | | + [#include <libavcodec/avcodec.h>]) |
320 | | + AC_CHECK_DECLS([CODEC_CAP_EXPERIMENTAL], , , |
321 | | + [#include <libavcodec/avcodec.h>]) |
322 | | + AC_SEARCH_LIBS(av_get_sample_fmt_name, avutil, |
323 | | + [AC_DEFINE([HAVE_AV_GET_SAMPLE_FMT_NAME], 1, |
324 | | + [Define to 1 if you have the `av_get_sample_fmt_name' function.])]) |
325 | | + AC_SEARCH_LIBS(av_lockmgr_register, avcodec, |
326 | | + [AC_DEFINE([HAVE_LOCKMGR_REGISTER], 1, |
327 | | + [Define to 1 if you have the `av_lockmgr_register' function.])]) |
328 | | CPPFLAGS="$save_CPPFLAGS" |
329 | | CFLAGS="$save_CFLAGS" |
330 | | LIBS="$save_LIBS" |
331 | | Index: decoder_plugins/ffmpeg/ffmpeg.c |
332 | | =================================================================== |
333 | | --- decoder_plugins/ffmpeg/ffmpeg.c (revision 2506) |
334 | | +++ decoder_plugins/ffmpeg/ffmpeg.c (revision 2529) |
335 | | @@ -99,6 +99,7 @@ |
336 | | bool okay; /* was this stream successfully opened? */ |
337 | | struct decoder_error error; |
338 | | long fmt; |
339 | | + int sample_width; |
340 | | int bitrate; /* in bits per second */ |
341 | | int avg_bitrate; /* in bits per second */ |
342 | | #if SEEK_IN_DECODER |
343 | | @@ -106,6 +107,7 @@ |
344 | | int seek_sec; /* second to which to seek */ |
345 | | #endif |
346 | | bool seek_broken; /* FFmpeg seeking is broken */ |
347 | | + bool timing_broken; /* FFmpeg trashes duration and bit_rate */ |
348 | | #if SEEK_IN_DECODER && defined(DEBUG) |
349 | | pthread_t thread_id; |
350 | | #endif |
351 | | @@ -277,8 +279,72 @@ |
352 | | } |
353 | | } |
354 | | |
355 | | +/* Handle FFmpeg's locking requirements. */ |
356 | | +#ifdef HAVE_LOCKMGR_REGISTER |
357 | | +static int locking_cb (void **mutex, enum AVLockOp op) |
358 | | +{ |
359 | | + int result; |
360 | | + |
361 | | + switch (op) { |
362 | | + case AV_LOCK_CREATE: |
363 | | + *mutex = xmalloc (sizeof (pthread_mutex_t)); |
364 | | + result = pthread_mutex_init (*mutex, NULL); |
365 | | + break; |
366 | | + case AV_LOCK_OBTAIN: |
367 | | + result = pthread_mutex_lock (*mutex); |
368 | | + break; |
369 | | + case AV_LOCK_RELEASE: |
370 | | + result = pthread_mutex_unlock (*mutex); |
371 | | + break; |
372 | | + case AV_LOCK_DESTROY: |
373 | | + result = pthread_mutex_destroy (*mutex); |
374 | | + free (*mutex); |
375 | | + *mutex = NULL; |
376 | | + break; |
377 | | + } |
378 | | + |
379 | | + return result; |
380 | | +} |
381 | | +#endif |
382 | | + |
383 | | +/* Here we attempt to determine if FFmpeg/LibAV has trashed the 'duration' |
384 | | + * and 'bit_rate' fields in AVFormatContext for large files. Determining |
385 | | + * whether or not they are likely to be valid is imprecise and will vary |
386 | | + * depending (at least) on: |
387 | | + * |
388 | | + * - The file's size, |
389 | | + * - The file's codec, |
390 | | + * - The number and size of tags, |
391 | | + * - The version of FFmpeg/LibAV, and |
392 | | + * - Whether it's FFmpeg or LibAV. |
393 | | + * |
394 | | + * This function represents a best guess. |
395 | | +*/ |
396 | | +static bool is_timing_broken (AVFormatContext *ic) |
397 | | +{ |
398 | | + int64_t file_size; |
399 | | + |
400 | | + if (ic->duration < 0 || ic->bit_rate < 0) |
401 | | + return true; |
402 | | + |
403 | | +#ifdef HAVE_AVIO_SIZE |
404 | | + file_size = avio_size (ic->pb); |
405 | | +#else |
406 | | + file_size = ic->file_size; |
407 | | +#endif |
408 | | + |
409 | | + if (file_size < UINT32_MAX) |
410 | | + return false; |
411 | | + |
412 | | + return true; |
413 | | +} |
414 | | + |
415 | | static void ffmpeg_init () |
416 | | { |
417 | | +#ifdef HAVE_LOCKMGR_REGISTER |
418 | | + int rc; |
419 | | +#endif |
420 | | + |
421 | | #ifdef DEBUG |
422 | | av_log_set_level (AV_LOG_INFO); |
423 | | #else |
424 | | @@ -291,10 +357,20 @@ |
425 | | supported_extns = lists_strs_new (16); |
426 | | load_audio_extns (supported_extns); |
427 | | load_video_extns (supported_extns); |
428 | | + |
429 | | +#ifdef HAVE_LOCKMGR_REGISTER |
430 | | + rc = av_lockmgr_register (locking_cb); |
431 | | + if (rc < 0) |
432 | | + fatal ("Lock manager initialisation failed"); |
433 | | +#endif |
434 | | } |
435 | | |
436 | | static void ffmpeg_destroy () |
437 | | { |
438 | | +#ifdef HAVE_LOCKMGR_REGISTER |
439 | | + av_lockmgr_register (NULL); |
440 | | +#endif |
441 | | + |
442 | | av_log_set_level (AV_LOG_QUIET); |
443 | | ffmpeg_log_repeats (NULL); |
444 | | |
445 | | @@ -341,9 +417,9 @@ |
446 | | } |
447 | | #endif |
448 | | |
449 | | - if (tags_sel & TAGS_TIME) { |
450 | | + if (!is_timing_broken (ic) && tags_sel & TAGS_TIME) { |
451 | | info->time = -1; |
452 | | - if (ic->duration >= 0) |
453 | | + if (ic->duration != (int64_t)AV_NOPTS_VALUE && ic->duration >= 0) |
454 | | info->time = ic->duration / AV_TIME_BASE; |
455 | | } |
456 | | |
457 | | @@ -426,12 +502,6 @@ |
458 | | |
459 | | #endif |
460 | | |
461 | | - if (tags_sel & TAGS_TIME) { |
462 | | - info->time = -1; |
463 | | - if (ic->duration != (int64_t)AV_NOPTS_VALUE && ic->duration >= 0) |
464 | | - info->time = ic->duration / AV_TIME_BASE; |
465 | | - } |
466 | | - |
467 | | end: |
468 | | #ifdef HAVE_AVFORMAT_CLOSE_INPUT |
469 | | avformat_close_input (&ic); |
470 | | @@ -450,6 +520,9 @@ |
471 | | if (!strcmp (data->ic->iformat->name, "wav")) { |
472 | | switch (data->enc->codec_id) { |
473 | | case CODEC_ID_PCM_S8: |
474 | | +#if HAVE_DECL_CODEC_ID_PCM_S8_PLANAR |
475 | | + case CODEC_ID_PCM_S8_PLANAR: |
476 | | +#endif |
477 | | result = SFMT_S8; |
478 | | break; |
479 | | case CODEC_ID_PCM_U8: |
480 | | @@ -456,6 +529,7 @@ |
481 | | result = SFMT_U8; |
482 | | break; |
483 | | case CODEC_ID_PCM_S16LE: |
484 | | + case CODEC_ID_PCM_S16LE_PLANAR: |
485 | | case CODEC_ID_PCM_S16BE: |
486 | | result = SFMT_S16; |
487 | | break; |
488 | | @@ -490,15 +564,27 @@ |
489 | | |
490 | | switch (data->enc->sample_fmt) { |
491 | | case AV_SAMPLE_FMT_U8: |
492 | | +#if HAVE_DECL_AV_SAMPLE_FMT_U8P |
493 | | + case AV_SAMPLE_FMT_U8P: |
494 | | +#endif |
495 | | result = SFMT_U8; |
496 | | break; |
497 | | case AV_SAMPLE_FMT_S16: |
498 | | +#if HAVE_DECL_AV_SAMPLE_FMT_S16P |
499 | | + case AV_SAMPLE_FMT_S16P: |
500 | | +#endif |
501 | | result = SFMT_S16; |
502 | | break; |
503 | | case AV_SAMPLE_FMT_S32: |
504 | | +#if HAVE_DECL_AV_SAMPLE_FMT_S32P |
505 | | + case AV_SAMPLE_FMT_S32P: |
506 | | +#endif |
507 | | result = SFMT_S32; |
508 | | break; |
509 | | case AV_SAMPLE_FMT_FLT: |
510 | | +#if HAVE_DECL_AV_SAMPLE_FMT_FLTP |
511 | | + case AV_SAMPLE_FMT_FLTP: |
512 | | +#endif |
513 | | result = SFMT_FLOAT; |
514 | | break; |
515 | | default: |
516 | | @@ -597,6 +683,7 @@ |
517 | | data->stream = NULL; |
518 | | data->enc = NULL; |
519 | | data->codec = NULL; |
520 | | + data->sample_width = 0; |
521 | | data->bitrate = 0; |
522 | | data->avg_bitrate = 0; |
523 | | |
524 | | @@ -624,6 +711,7 @@ |
525 | | data->seek_sec = 0; |
526 | | #endif |
527 | | data->seek_broken = false; |
528 | | + data->timing_broken = false; |
529 | | |
530 | | decoder_error_init (&data->error); |
531 | | |
532 | | @@ -655,6 +743,9 @@ |
533 | | err = av_find_stream_info (data->ic); |
534 | | #endif |
535 | | if (err < 0) { |
536 | | + /* Depending on the particular FFmpeg/LibAV version in use, this |
537 | | + * may misreport experimental codecs. Given we don't know the |
538 | | + * codec at this time, we will have to live with it. */ |
539 | | decoder_error (&data->error, ERROR_FATAL, 0, |
540 | | "Could not find codec parameters (err %d)", |
541 | | err); |
542 | | @@ -683,6 +774,19 @@ |
543 | | debug ("FFmpeg thinks '%s' is format(codec) '%s(%s)'", |
544 | | fn, data->ic->iformat->name, data->codec->name); |
545 | | |
546 | | +#if HAVE_DECL_CODEC_CAP_EXPERIMENTAL |
547 | | + /* This may or may not work depending on the particular version of |
548 | | + * FFmpeg/LibAV in use. For some versions this will be caught in |
549 | | + * *_find_stream_info() above and misreported as an unfound codec |
550 | | + * parameters error. */ |
551 | | + if (data->codec->capabilities & CODEC_CAP_EXPERIMENTAL) { |
552 | | + decoder_error (&data->error, ERROR_FATAL, 0, |
553 | | + "The codec is experimental and may damage MOC: %s", |
554 | | + data->codec->name); |
555 | | + goto end; |
556 | | + } |
557 | | +#endif |
558 | | + |
559 | | set_downmixing (data); |
560 | | if (data->codec->capabilities & CODEC_CAP_TRUNCATED) |
561 | | data->enc->flags |= CODEC_FLAG_TRUNCATED; |
562 | | @@ -702,27 +806,38 @@ |
563 | | if (data->fmt == 0) |
564 | | data->fmt = fmt_from_sample_fmt (data); |
565 | | if (data->fmt == 0) { |
566 | | +#ifdef HAVE_AV_GET_SAMPLE_FMT_NAME |
567 | | decoder_error (&data->error, ERROR_FATAL, 0, |
568 | | + "Cannot get sample size from unknown sample format: %s", |
569 | | + av_get_sample_fmt_name (data->enc->sample_fmt)); |
570 | | +#else |
571 | | + decoder_error (&data->error, ERROR_FATAL, 0, |
572 | | "Unsupported sample size!"); |
573 | | +#endif |
574 | | + avcodec_close (data->enc); |
575 | | goto end; |
576 | | } |
577 | | + data->sample_width = sfmt_Bps (data->fmt); |
578 | | if (data->codec->capabilities & CODEC_CAP_DELAY) |
579 | | data->delay = true; |
580 | | data->seek_broken = is_seek_broken (data); |
581 | | + data->timing_broken = is_timing_broken (data->ic); |
582 | | |
583 | | data->okay = true; |
584 | | |
585 | | - if (data->ic->duration >= AV_TIME_BASE) { |
586 | | + if (!data->timing_broken && data->ic->duration >= AV_TIME_BASE) { |
587 | | #ifdef HAVE_AVIO_SIZE |
588 | | data->avg_bitrate = (int) (avio_size (data->ic->pb) / |
589 | | - (data->ic->duration / AV_TIME_BASE) * 8); |
590 | | + (data->ic->duration / AV_TIME_BASE) * 8); |
591 | | #else |
592 | | data->avg_bitrate = (int) (data->ic->file_size / |
593 | | - (data->ic->duration / AV_TIME_BASE) * 8); |
594 | | + (data->ic->duration / AV_TIME_BASE) * 8); |
595 | | #endif |
596 | | } |
597 | | - data->bitrate = data->ic->bit_rate; |
598 | | |
599 | | + if (!data->timing_broken && data->ic->bit_rate > 0) |
600 | | + data->bitrate = data->ic->bit_rate; |
601 | | + |
602 | | return data; |
603 | | |
604 | | end: |
605 | | @@ -908,8 +1023,6 @@ |
606 | | &data_size, pkt->data, pkt->size); |
607 | | #endif |
608 | | |
609 | | - debug ("Decoded %dB", data_size); |
610 | | - |
611 | | if (len < 0) { |
612 | | /* skip frame */ |
613 | | decoder_error (&data->error, ERROR_STREAM, 0, "Error in the stream!"); |
614 | | @@ -916,14 +1029,16 @@ |
615 | | break; |
616 | | } |
617 | | |
618 | | + debug ("Decoded %dB", data_size); |
619 | | + |
620 | | + pkt->data += len; |
621 | | + pkt->size -= len; |
622 | | + |
623 | | if (data->eof && data_size == 0) { |
624 | | data->eos = true; |
625 | | break; |
626 | | } |
627 | | |
628 | | - pkt->data += len; |
629 | | - pkt->size -= len; |
630 | | - |
631 | | copied = copy_or_buffer (data, data->avbuf, data_size, buf, buf_len); |
632 | | |
633 | | buf += copied; |
634 | | @@ -943,12 +1058,15 @@ |
635 | | char *buf, int buf_len) |
636 | | { |
637 | | int filled = 0; |
638 | | + char *packed; |
639 | | + AVFrame *frame; |
640 | | |
641 | | + frame = avcodec_alloc_frame (); |
642 | | + |
643 | | do { |
644 | | - int len, got_frame, is_planar, plane_size, data_size, copied; |
645 | | - AVFrame frame; |
646 | | + int len, got_frame, is_planar, packed_size, copied; |
647 | | |
648 | | - len = avcodec_decode_audio4 (data->enc, &frame, &got_frame, pkt); |
649 | | + len = avcodec_decode_audio4 (data->enc, frame, &got_frame, pkt); |
650 | | |
651 | | if (len < 0) { |
652 | | /* skip frame */ |
653 | | @@ -956,45 +1074,56 @@ |
654 | | break; |
655 | | } |
656 | | |
657 | | - if (!got_frame) { |
658 | | - data->eos = data->eof; |
659 | | - break; |
660 | | - } |
661 | | - |
662 | | debug ("Decoded %dB", len); |
663 | | |
664 | | pkt->data += len; |
665 | | pkt->size -= len; |
666 | | |
667 | | - is_planar = av_sample_fmt_is_planar (data->enc->sample_fmt); |
668 | | - data_size = av_samples_get_buffer_size (&plane_size, |
669 | | - data->enc->channels, frame.nb_samples, |
670 | | - data->enc->sample_fmt, 1); |
671 | | + if (!got_frame) { |
672 | | + data->eos = data->eof && (pkt->size == 0); |
673 | | + continue; |
674 | | + } |
675 | | |
676 | | - if (data_size == 0) |
677 | | + if (frame->nb_samples == 0) |
678 | | continue; |
679 | | |
680 | | - copied = copy_or_buffer (data, (char *)frame.extended_data[0], |
681 | | - plane_size, buf, buf_len); |
682 | | + is_planar = av_sample_fmt_is_planar (data->enc->sample_fmt); |
683 | | + packed = (char *)frame->extended_data[0]; |
684 | | + packed_size = frame->nb_samples * data->sample_width |
685 | | + * data->enc->channels; |
686 | | + |
687 | | + if (is_planar && data->enc->channels > 1) { |
688 | | + int sample, ch; |
689 | | + |
690 | | + packed = xmalloc (packed_size); |
691 | | + |
692 | | + for (sample = 0; sample < frame->nb_samples; sample += 1) { |
693 | | + for (ch = 0; ch < data->enc->channels; ch += 1) |
694 | | + memcpy (packed + (sample * data->enc->channels + ch) |
695 | | + * data->sample_width, |
696 | | + (char *)frame->extended_data[ch] + sample * data->sample_width, |
697 | | + data->sample_width); |
698 | | + } |
699 | | + } |
700 | | + |
701 | | + copied = copy_or_buffer (data, packed, packed_size, buf, buf_len); |
702 | | buf += copied; |
703 | | filled += copied; |
704 | | buf_len -= copied; |
705 | | |
706 | | - if (is_planar && data->enc->channels > 1) { |
707 | | - int ch; |
708 | | + debug ("Copying %dB (%dB filled)", packed_size, filled); |
709 | | |
710 | | - for (ch = 1; ch < data->enc->channels; ch += 1) { |
711 | | - copied = copy_or_buffer (data, (char *)frame.extended_data[ch], |
712 | | - plane_size, buf, buf_len); |
713 | | - buf += copied; |
714 | | - filled += copied; |
715 | | - buf_len -= copied; |
716 | | - } |
717 | | - } |
718 | | - |
719 | | - debug ("Copying %dB (%dB filled)", data_size, filled); |
720 | | + if (packed != (char *)frame->extended_data[0]) |
721 | | + free (packed); |
722 | | } while (pkt->size > 0); |
723 | | |
724 | | + avcodec_get_frame_defaults (frame); |
725 | | +#ifdef HAVE_AVCODEC_FREE_FRAME |
726 | | + avcodec_free_frame (&frame); |
727 | | +#else |
728 | | + av_freep (&frame); |
729 | | +#endif |
730 | | + |
731 | | return filled; |
732 | | } |
733 | | #endif |
734 | | @@ -1122,9 +1251,10 @@ |
735 | | free_packet (pkt); |
736 | | } while (!bytes_produced && !data->eos); |
737 | | |
738 | | - data->bitrate = compute_bitrate (sound_params, bytes_used, |
739 | | - bytes_produced + data->remain_buf_len, |
740 | | - data->bitrate); |
741 | | + if (!data->timing_broken) |
742 | | + data->bitrate = compute_bitrate (sound_params, bytes_used, |
743 | | + bytes_produced + data->remain_buf_len, |
744 | | + data->bitrate); |
745 | | |
746 | | return bytes_produced; |
747 | | } |
748 | | @@ -1185,7 +1315,7 @@ |
749 | | { |
750 | | struct ffmpeg_data *data = (struct ffmpeg_data *)prv_data; |
751 | | |
752 | | - return data->bitrate / 1000; |
753 | | + return data->timing_broken ? -1 : data->bitrate / 1000; |
754 | | } |
755 | | |
756 | | static int ffmpeg_get_avg_bitrate (void *prv_data) |
757 | | @@ -1192,7 +1322,7 @@ |
758 | | { |
759 | | struct ffmpeg_data *data = (struct ffmpeg_data *)prv_data; |
760 | | |
761 | | - return data->avg_bitrate / 1000; |
762 | | + return data->timing_broken ? -1 : data->avg_bitrate / 1000; |
763 | | } |
764 | | |
765 | | static int ffmpeg_get_duration (void *prv_data) |
766 | | @@ -1199,6 +1329,9 @@ |
767 | | { |
768 | | struct ffmpeg_data *data = (struct ffmpeg_data *)prv_data; |
769 | | |
770 | | + if (data->timing_broken) |
771 | | + return -1; |
772 | | + |
773 | | if (!data->stream) |
774 | | return -1; |
775 | | |
776 | | Index: decoder_plugins/vorbis/vorbis.c |
777 | | =================================================================== |
778 | | --- decoder_plugins/vorbis/vorbis.c (revision 2506) |
779 | | +++ decoder_plugins/vorbis/vorbis.c (revision 2529) |
780 | | @@ -47,9 +47,9 @@ |
781 | | |
782 | | /* Tremor defines time as 64-bit integer milliseconds. */ |
783 | | #ifndef HAVE_TREMOR |
784 | | -static const double time_scaler = 1; |
785 | | +static const int64_t time_scaler = 1; |
786 | | #else |
787 | | -static const ogg_int64_t time_scaler = 1000; |
788 | | +static const int64_t time_scaler = 1000; |
789 | | #endif |
790 | | |
791 | | struct vorbis_data |
792 | | @@ -171,11 +171,11 @@ |
793 | | get_comment_tags (&vf, info); |
794 | | |
795 | | if (tags_sel & TAGS_TIME) { |
796 | | - int vorbis_time; |
797 | | + int64_t vorbis_time; |
798 | | |
799 | | - vorbis_time = ov_time_total (&vf, -1) / time_scaler; |
800 | | - if (vorbis_time >= 0) |
801 | | - info->time = vorbis_time; |
802 | | + vorbis_time = ov_time_total (&vf, -1); |
803 | | + if (vorbis_time >= 0) |
804 | | + info->time = vorbis_time / time_scaler; |
805 | | } |
806 | | |
807 | | ov_clear (&vf); |
808 | | @@ -244,12 +244,15 @@ |
809 | | io_close (data->stream); |
810 | | } |
811 | | else { |
812 | | + int64_t duration; |
813 | | + |
814 | | data->last_section = -1; |
815 | | data->avg_bitrate = ov_bitrate (&data->vf, -1) / 1000; |
816 | | data->bitrate = data->avg_bitrate; |
817 | | - data->duration = ov_time_total (&data->vf, -1) / time_scaler; |
818 | | - if (data->duration == OV_EINVAL) |
819 | | - data->duration = -1; |
820 | | + data->duration = -1; |
821 | | + duration = ov_time_total (&data->vf, -1); |
822 | | + if (duration >= 0) |
823 | | + data->duration = duration / time_scaler; |
824 | | data->ok = 1; |
825 | | get_comment_tags (&data->vf, data->tags); |
826 | | } |
827 | | @@ -280,9 +283,9 @@ |
828 | | |
829 | | static int vorbis_can_decode (struct io_stream *stream) |
830 | | { |
831 | | - char buf[34]; |
832 | | + char buf[35]; |
833 | | |
834 | | - if (io_peek (stream, buf, 34) == 34 && !memcmp (buf, "OggS", 4) |
835 | | + if (io_peek (stream, buf, 35) == 35 && !memcmp (buf, "OggS", 4) |
836 | | && !memcmp (buf + 28, "\01vorbis", 7)) |
837 | | return 1; |
838 | | |
839 | | Index: decoder_plugins/flac/flac.c |
840 | | =================================================================== |
841 | | --- decoder_plugins/flac/flac.c (revision 2506) |
842 | | +++ decoder_plugins/flac/flac.c (revision 2529) |
843 | | @@ -54,7 +54,7 @@ |
844 | | int abort; /* abort playing (due to an error) */ |
845 | | |
846 | | unsigned length; |
847 | | - unsigned total_samples; |
848 | | + FLAC__uint64 total_samples; |
849 | | |
850 | | FLAC__byte sample_buffer[SAMPLE_BUFFER_SIZE]; |
851 | | unsigned sample_buffer_fill; |
852 | | @@ -156,11 +156,8 @@ |
853 | | if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) { |
854 | | debug ("Got metadata info"); |
855 | | |
856 | | - data->total_samples = |
857 | | - (unsigned)(metadata->data.stream_info.total_samples |
858 | | - & 0xffffffff); |
859 | | - data->bits_per_sample = |
860 | | - metadata->data.stream_info.bits_per_sample; |
861 | | + data->total_samples = metadata->data.stream_info.total_samples; |
862 | | + data->bits_per_sample = metadata->data.stream_info.bits_per_sample; |
863 | | data->channels = metadata->data.stream_info.channels; |
864 | | data->sample_rate = metadata->data.stream_info.sample_rate; |
865 | | data->length = data->total_samples / data->sample_rate; |
866 | | @@ -536,9 +533,10 @@ |
867 | | if ((unsigned)sec > data->length) |
868 | | return -1; |
869 | | |
870 | | - target_sample = (FLAC__uint64)((sec/(double)data->length) * |
871 | | - (double)data->total_samples); |
872 | | + target_sample = (FLAC__uint64)(((double)sec / (double)data->length) * |
873 | | + (double)data->total_samples); |
874 | | |
875 | | + |
876 | | #ifdef LEGACY_FLAC |
877 | | if (FLAC__seekable_stream_decoder_seek_absolute(data->decoder, |
878 | | target_sample)) |
879 | | Index: audio.c |
880 | | =================================================================== |
881 | | --- audio.c (revision 2506) |
882 | | +++ audio.c (revision 2529) |
883 | | @@ -169,7 +169,7 @@ |
884 | | if (fmt1 & (SFMT_S16 | SFMT_U16) |
885 | | && fmt2 & (SFMT_S16 | SFMT_U16)) |
886 | | return 1; |
887 | | - if (fmt1 & (SFMT_S8 | SFMT_U8) |
888 | | + if (fmt1 & (SFMT_S32 | SFMT_U32) |
889 | | && fmt2 & (SFMT_S32 | SFMT_U32)) |
890 | | return 1; |
891 | | if (fmt1 & fmt2 & SFMT_FLOAT) |
892 | | Index: TODO |
893 | | =================================================================== |
894 | | --- TODO (revision 2506) |
895 | | +++ TODO (revision 2529) |
896 | | @@ -9,8 +9,6 @@ |
897 | | - Recognition of ID3 tags v1 is broken (example: small.mp3). [node/234] |
898 | | - Perhaps MOC can add support for the frame field_type to differentiate |
899 | | between ID3_FIELD_TYPE_LATIN1 and ID3_FIELD_TYPE_STRING. [node/234] |
900 | | - - Characters which are represented in more than one screen column cause |
901 | | - the text to overflow its field. [node/82, 99 and 788] |
902 | | - Some Cyrillic characters in file and directory names don't get displayed |
903 | | correctly. |
904 | | * Program crashes: |