Mercurial > audlegacy-plugins
comparison src/ffmpeg/ffmpeg.c @ 814:2eaaa3aa182b trunk
[svn] - make the whole thing compile. runtime linking is another story.
| author | nenolod |
|---|---|
| date | Mon, 12 Mar 2007 13:00:06 -0700 |
| parents | src/ffmpeg/wma.c@74abcb9cafae |
| children | 07107d476f32 |
comparison
equal
deleted
inserted
replaced
| 813:1d03ded97d44 | 814:2eaaa3aa182b |
|---|---|
| 1 /* | |
| 2 * Audacious WMA input plugin | |
| 3 * (C) 2005 Audacious development team | |
| 4 * | |
| 5 * Based on: | |
| 6 * xmms-wma - WMA player for BMP | |
| 7 * Copyright (C) 2004,2005 McMCC <mcmcc@mail.ru> | |
| 8 * bmp-wma - WMA player for BMP | |
| 9 * Copyright (C) 2004 Roman Bogorodskiy <bogorodskiy@inbox.ru> | |
| 10 * | |
| 11 * This program is free software; you can redistribute it and/or modify | |
| 12 * it under the terms of the GNU General Public License as published by | |
| 13 * the Free Software Foundation; either version 2 of the License, or | |
| 14 * (at your option) any later version. | |
| 15 * | |
| 16 * This program is distributed in the hope that it will be useful, | |
| 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 19 * GNU General Public License for more details. | |
| 20 * | |
| 21 * You should have received a copy of the GNU General Public License | |
| 22 * along with this program; if not, write to the Free Software | |
| 23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
| 24 */ | |
| 25 #define _XOPEN_SOURCE 600 | |
| 26 #include <stdlib.h> | |
| 27 #include <unistd.h> | |
| 28 #include <math.h> | |
| 29 #include <stdbool.h> | |
| 30 #include <stdio.h> | |
| 31 #include <string.h> | |
| 32 #include <strings.h> | |
| 33 #include <glib.h> | |
| 34 | |
| 35 #include <audacious/plugin.h> | |
| 36 #include <audacious/output.h> | |
| 37 #include <audacious/util.h> | |
| 38 #include <audacious/titlestring.h> | |
| 39 #include <audacious/vfs.h> | |
| 40 #include <audacious/strings.h> | |
| 41 #include <audacious/i18n.h> | |
| 42 | |
| 43 #include "avcodec.h" | |
| 44 #include "avformat.h" | |
| 45 | |
| 46 #define ABOUT_TXT "Adapted for use in audacious by Tony Vroon (chainsaw@gentoo.org) from\n \ | |
| 47 the BEEP-WMA plugin which is Copyright (C) 2004,2005 Mokrushin I.V. aka McMCC (mcmcc@mail.ru)\n \ | |
| 48 and the BMP-WMA plugin which is Copyright (C) 2004 Roman Bogorodskiy <bogorodskiy@inbox.ru>.\n \ | |
| 49 This plugin based on source code " LIBAVCODEC_IDENT "\nby Fabrice Bellard from \ | |
| 50 http://ffmpeg.sourceforge.net.\n\n \ | |
| 51 This program is free software; you can redistribute it and/or modify \n \ | |
| 52 it under the terms of the GNU General Public License as published by \n \ | |
| 53 the Free Software Foundation; either version 2 of the License, or \n \ | |
| 54 (at your option) any later version. \n\n \ | |
| 55 This program is distributed in the hope that it will be useful, \n \ | |
| 56 but WITHOUT ANY WARRANTY; without even the implied warranty of \n \ | |
| 57 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. \n \ | |
| 58 See the GNU General Public License for more details.\n" | |
| 59 #define PLUGIN_NAME "Audacious-WMA" | |
| 60 #define PLUGIN_VERSION "v.1.0.5" | |
| 61 #define ST_BUFF 1024 | |
| 62 | |
| 63 static int wma_decode = 0; | |
| 64 static gboolean wma_pause = 0; | |
| 65 static int wma_seekpos = -1; | |
| 66 static int wma_st_buff, wma_idx, wma_idx2; | |
| 67 static GThread *wma_decode_thread; | |
| 68 GStaticMutex wma_mutex = G_STATIC_MUTEX_INIT; | |
| 69 static AVCodecContext *c = NULL; | |
| 70 static AVFormatContext *ic = NULL; | |
| 71 static AVCodecContext *c2 = NULL; | |
| 72 static AVFormatContext *ic2 = NULL; | |
| 73 static uint8_t *wma_outbuf, *wma_s_outbuf; | |
| 74 | |
| 75 char description[64]; | |
| 76 static void wma_about(void); | |
| 77 static void wma_init(void); | |
| 78 static int wma_is_our_file(char *filename); | |
| 79 static int wma_is_our_fd(char *filename, VFSFile *fd); | |
| 80 static void wma_play_file(InputPlayback *data); | |
| 81 static void wma_stop(InputPlayback *data); | |
| 82 static void wma_seek(InputPlayback *data, int time); | |
| 83 static void wma_do_pause(InputPlayback *data, short p); | |
| 84 static int wma_get_time(InputPlayback *data); | |
| 85 static void wma_get_song_info(char *filename, char **title, int *length); | |
| 86 static TitleInput *wma_get_song_tuple(char *filename); | |
| 87 static char *wsong_title; | |
| 88 static int wsong_time; | |
| 89 | |
| 90 static GtkWidget *dialog1, *button1, *label1; | |
| 91 | |
| 92 InputPlugin *get_iplugin_info(void); | |
| 93 | |
| 94 gchar *wma_fmts[] = { "wma", NULL }; | |
| 95 | |
| 96 InputPlugin wma_ip = | |
| 97 { | |
| 98 NULL, // Filled in by xmms | |
| 99 NULL, // Filled in by xmms | |
| 100 description, // The description that is shown in the preferences box | |
| 101 wma_init, // Called when the plugin is loaded | |
| 102 wma_about, // Show the about box | |
| 103 NULL, // Show the configure box | |
| 104 wma_is_our_file, // Return 1 if the plugin can handle the file | |
| 105 NULL, // Scan dir | |
| 106 wma_play_file, // Play file | |
| 107 wma_stop, // Stop | |
| 108 wma_do_pause, // Pause | |
| 109 wma_seek, // Seek | |
| 110 NULL, // Set the equalizer, most plugins won't be able to do this | |
| 111 wma_get_time, // Get the time, usually returns the output plugins output time | |
| 112 NULL, // Get volume | |
| 113 NULL, // Set volume | |
| 114 NULL, // OBSOLETE! | |
| 115 NULL, // OBSOLETE! | |
| 116 NULL, // Send data to the visualization plugins | |
| 117 NULL, // Fill in the stuff that is shown in the player window | |
| 118 NULL, // Show some text in the song title box. Filled in by xmms | |
| 119 wma_get_song_info, // Function to grab the title string | |
| 120 NULL, // Bring up an info window for the filename passed in | |
| 121 NULL, // Handle to the current output plugin. Filled in by xmms | |
| 122 wma_get_song_tuple, // Tuple builder | |
| 123 NULL, | |
| 124 NULL, | |
| 125 wma_is_our_fd, // vfs | |
| 126 wma_fmts | |
| 127 }; | |
| 128 | |
| 129 InputPlugin *get_iplugin_info(void) | |
| 130 { | |
| 131 memset(description, 0, 64); | |
| 132 wma_ip.description = g_strdup_printf(_("WMA Player %s"), PACKAGE_VERSION); | |
| 133 return &wma_ip; | |
| 134 } | |
| 135 | |
| 136 static gchar *str_twenty_to_space(gchar * str) | |
| 137 { | |
| 138 gchar *match, *match_end; | |
| 139 | |
| 140 g_return_val_if_fail(str != NULL, NULL); | |
| 141 | |
| 142 while ((match = strstr(str, "%20"))) { | |
| 143 match_end = match + 3; | |
| 144 *match++ = ' '; | |
| 145 while (*match_end) | |
| 146 *match++ = *match_end++; | |
| 147 *match = 0; | |
| 148 } | |
| 149 | |
| 150 return str; | |
| 151 } | |
| 152 | |
| 153 static void wma_about(void) | |
| 154 { | |
| 155 char *title; | |
| 156 char *message; | |
| 157 | |
| 158 if (dialog1) return; | |
| 159 | |
| 160 title = (char *)g_malloc(80); | |
| 161 message = (char *)g_malloc(1000); | |
| 162 memset(title, 0, 80); | |
| 163 memset(message, 0, 1000); | |
| 164 | |
| 165 sprintf(title, _("About %s"), PLUGIN_NAME); | |
| 166 sprintf(message, "%s %s\n\n%s", PLUGIN_NAME, PLUGIN_VERSION, ABOUT_TXT); | |
| 167 | |
| 168 dialog1 = gtk_dialog_new(); | |
| 169 g_signal_connect(G_OBJECT(dialog1), "destroy", | |
| 170 G_CALLBACK(gtk_widget_destroyed), &dialog1); | |
| 171 gtk_window_set_title(GTK_WINDOW(dialog1), title); | |
| 172 gtk_window_set_policy(GTK_WINDOW(dialog1), FALSE, FALSE, FALSE); | |
| 173 gtk_container_border_width(GTK_CONTAINER(dialog1), 5); | |
| 174 label1 = gtk_label_new(message); | |
| 175 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog1)->vbox), label1, TRUE, TRUE, 0); | |
| 176 gtk_widget_show(label1); | |
| 177 | |
| 178 button1 = gtk_button_new_with_label(_(" Close ")); | |
| 179 g_signal_connect_swapped(G_OBJECT(button1), "clicked", | |
| 180 G_CALLBACK(gtk_widget_destroy), | |
| 181 GTK_OBJECT(dialog1)); | |
| 182 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog1)->action_area), button1, | |
| 183 FALSE, FALSE, 0); | |
| 184 | |
| 185 gtk_widget_show(button1); | |
| 186 gtk_widget_show(dialog1); | |
| 187 gtk_widget_grab_focus(button1); | |
| 188 g_free(title); | |
| 189 g_free(message); | |
| 190 } | |
| 191 | |
| 192 static void wma_init(void) | |
| 193 { | |
| 194 avcodec_init(); | |
| 195 avcodec_register_all(); | |
| 196 av_register_all(); | |
| 197 } | |
| 198 | |
| 199 static int wma_is_our_file(char *filename) | |
| 200 { | |
| 201 AVCodec *codec2; | |
| 202 | |
| 203 if(av_open_input_file(&ic2, str_twenty_to_space(filename), NULL, 0, NULL) < 0) return 0; | |
| 204 | |
| 205 for(wma_idx2 = 0; wma_idx2 < ic2->nb_streams; wma_idx2++) { | |
| 206 c2 = &ic2->streams[wma_idx2]->codec; | |
| 207 if(c2->codec_type == CODEC_TYPE_AUDIO) break; | |
| 208 } | |
| 209 | |
| 210 av_find_stream_info(ic2); | |
| 211 | |
| 212 codec2 = avcodec_find_decoder(c2->codec_id); | |
| 213 | |
| 214 if(!codec2) { | |
| 215 av_close_input_file(ic2); | |
| 216 return 0; | |
| 217 } | |
| 218 | |
| 219 av_close_input_file(ic2); | |
| 220 return 1; | |
| 221 } | |
| 222 | |
| 223 static int wma_is_our_fd(char *filename, VFSFile *fd) | |
| 224 { | |
| 225 AVCodec *codec2; | |
| 226 | |
| 227 if(av_open_input_vfsfile(&ic2, filename, fd, NULL, 0, NULL) < 0) return 0; | |
| 228 | |
| 229 for(wma_idx2 = 0; wma_idx2 < ic2->nb_streams; wma_idx2++) { | |
| 230 c2 = &ic2->streams[wma_idx2]->codec; | |
| 231 if(c2->codec_type == CODEC_TYPE_AUDIO) break; | |
| 232 } | |
| 233 | |
| 234 av_find_stream_info(ic2); | |
| 235 | |
| 236 codec2 = avcodec_find_decoder(c2->codec_id); | |
| 237 | |
| 238 return 1; | |
| 239 } | |
| 240 | |
| 241 static void wma_do_pause(InputPlayback *playback, short p) | |
| 242 { | |
| 243 wma_pause = p; | |
| 244 playback->output->pause(wma_pause); | |
| 245 } | |
| 246 | |
| 247 static void wma_seek(InputPlayback *playback, int time) | |
| 248 { | |
| 249 wma_seekpos = time; | |
| 250 if(wma_pause) playback->output->pause(0); | |
| 251 while(wma_decode && wma_seekpos!=-1) xmms_usleep(10000); | |
| 252 if(wma_pause) playback->output->pause(1); | |
| 253 } | |
| 254 | |
| 255 static int wma_get_time(InputPlayback *playback) | |
| 256 { | |
| 257 playback->output->buffer_free(); | |
| 258 if(wma_decode) return playback->output->output_time(); | |
| 259 return -1; | |
| 260 } | |
| 261 | |
| 262 static gchar *extname(const char *filename) | |
| 263 { | |
| 264 gchar *ext = strrchr(filename, '.'); | |
| 265 if(ext != NULL) ++ext; | |
| 266 return ext; | |
| 267 } | |
| 268 | |
| 269 static char* w_getstr(char* str) | |
| 270 { | |
| 271 if(str && strlen(str) > 0) return g_strdup(str); | |
| 272 return NULL; | |
| 273 } | |
| 274 | |
| 275 static TitleInput *wma_get_song_tuple(gchar * filename) | |
| 276 { | |
| 277 TitleInput *tuple = NULL; | |
| 278 AVFormatContext *in = NULL; | |
| 279 gchar *filename_proxy = g_strdup(filename); | |
| 280 | |
| 281 if (av_open_input_file(&in, str_twenty_to_space(filename), NULL, 0, NULL) < 0) | |
| 282 return NULL; | |
| 283 | |
| 284 tuple = bmp_title_input_new(); | |
| 285 | |
| 286 tuple->file_name = g_path_get_basename(filename_proxy); | |
| 287 tuple->file_path = g_path_get_dirname(filename_proxy); | |
| 288 tuple->file_ext = extname(filename_proxy); | |
| 289 | |
| 290 av_find_stream_info(in); | |
| 291 | |
| 292 if((in->title[0] != '\0') || (in->author[0] != '\0') || (in->album[0] != '\0') || | |
| 293 (in->comment[0] != '\0') || (in->genre[0] != '\0') || (in->year != 0) || (in->track != 0)) | |
| 294 { | |
| 295 tuple->performer = str_to_utf8(w_getstr(in->author)); | |
| 296 tuple->album_name = str_to_utf8(w_getstr(in->album)); | |
| 297 tuple->track_name = str_to_utf8(w_getstr(in->title)); | |
| 298 tuple->year = in->year; | |
| 299 tuple->track_number = in->track; | |
| 300 tuple->genre = str_to_utf8(w_getstr(in->genre)); | |
| 301 tuple->comment = str_to_utf8(w_getstr(in->comment)); | |
| 302 } | |
| 303 | |
| 304 if (in->duration) | |
| 305 tuple->length = in->duration / 1000; | |
| 306 | |
| 307 av_close_input_file(in); | |
| 308 | |
| 309 return tuple; | |
| 310 } | |
| 311 | |
| 312 static gchar *get_song_title(AVFormatContext *in, gchar * filename) | |
| 313 { | |
| 314 gchar *ret = NULL; | |
| 315 TitleInput *input; | |
| 316 | |
| 317 input = bmp_title_input_new(); | |
| 318 | |
| 319 if((in->title[0] != '\0') || (in->author[0] != '\0') || (in->album[0] != '\0') || | |
| 320 (in->comment[0] != '\0') || (in->genre[0] != '\0') || (in->year != 0) || (in->track != 0)) | |
| 321 { | |
| 322 input->performer = w_getstr(in->author); | |
| 323 input->album_name = w_getstr(in->album); | |
| 324 input->track_name = w_getstr(in->title); | |
| 325 input->year = in->year; | |
| 326 input->track_number = in->track; | |
| 327 input->genre = w_getstr(in->genre); | |
| 328 input->comment = w_getstr(in->comment); | |
| 329 } | |
| 330 input->file_name = g_path_get_basename(filename); | |
| 331 input->file_path = g_path_get_dirname(filename); | |
| 332 input->file_ext = extname(filename); | |
| 333 ret = xmms_get_titlestring(xmms_get_gentitle_format(), input); | |
| 334 if(input) g_free(input); | |
| 335 | |
| 336 if(!ret) | |
| 337 { | |
| 338 ret = g_strdup(input->file_name); | |
| 339 if (extname(ret) != NULL) | |
| 340 *(extname(ret) - 1) = '\0'; | |
| 341 } | |
| 342 return ret; | |
| 343 } | |
| 344 | |
| 345 static guint get_song_time(AVFormatContext *in) | |
| 346 { | |
| 347 if(in->duration) | |
| 348 return in->duration/1000; | |
| 349 else | |
| 350 return 0; | |
| 351 } | |
| 352 | |
| 353 static void wma_get_song_info(char *filename, char **title_real, int *len_real) | |
| 354 { | |
| 355 TitleInput *tuple = wma_get_song_tuple(filename); | |
| 356 | |
| 357 if (tuple == NULL) | |
| 358 return; | |
| 359 | |
| 360 (*len_real) = tuple->length; | |
| 361 (*title_real) = xmms_get_titlestring(xmms_get_gentitle_format(), tuple); | |
| 362 } | |
| 363 | |
| 364 static void wma_playbuff(InputPlayback *playback, int out_size) | |
| 365 { | |
| 366 FifoBuffer f; | |
| 367 int sst_buff; | |
| 368 | |
| 369 fifo_init(&f, out_size*2); | |
| 370 fifo_write(&f, wma_outbuf, out_size, &f.wptr); | |
| 371 while(!fifo_read(&f, wma_s_outbuf, wma_st_buff, &f.rptr) && wma_decode) | |
| 372 { | |
| 373 sst_buff = wma_st_buff; | |
| 374 if(wma_pause) memset(wma_s_outbuf, 0, sst_buff); | |
| 375 while(playback->output->buffer_free() < wma_st_buff) xmms_usleep(20000); | |
| 376 produce_audio(playback->output->written_time(), FMT_S16_NE, | |
| 377 c->channels, sst_buff, (short *)wma_s_outbuf, NULL); | |
| 378 memset(wma_s_outbuf, 0, sst_buff); | |
| 379 } | |
| 380 fifo_free(&f); | |
| 381 return; | |
| 382 } | |
| 383 | |
| 384 static void *wma_play_loop(void *arg) | |
| 385 { | |
| 386 InputPlayback *playback = arg; | |
| 387 uint8_t *inbuf_ptr; | |
| 388 int out_size, size, len; | |
| 389 AVPacket pkt; | |
| 390 | |
| 391 g_static_mutex_lock(&wma_mutex); | |
| 392 while(wma_decode){ | |
| 393 | |
| 394 if(wma_seekpos != -1) | |
| 395 { | |
| 396 av_seek_frame(ic, wma_idx, wma_seekpos * 1000000LL); | |
| 397 playback->output->flush(wma_seekpos * 1000); | |
| 398 wma_seekpos = -1; | |
| 399 } | |
| 400 | |
| 401 if(av_read_frame(ic, &pkt) < 0) break; | |
| 402 | |
| 403 size = pkt.size; | |
| 404 inbuf_ptr = pkt.data; | |
| 405 | |
| 406 if(size == 0) break; | |
| 407 | |
| 408 while(size > 0){ | |
| 409 len = avcodec_decode_audio(c, (short *)wma_outbuf, &out_size, | |
| 410 inbuf_ptr, size); | |
| 411 if(len < 0) break; | |
| 412 | |
| 413 if(out_size <= 0) continue; | |
| 414 | |
| 415 wma_playbuff(playback, out_size); | |
| 416 | |
| 417 size -= len; | |
| 418 inbuf_ptr += len; | |
| 419 if(pkt.data) av_free_packet(&pkt); | |
| 420 } | |
| 421 } | |
| 422 while(wma_decode && playback->output->buffer_playing()) xmms_usleep(30000); | |
| 423 wma_decode = 0; | |
| 424 if(wma_s_outbuf) g_free(wma_s_outbuf); | |
| 425 if(wma_outbuf) g_free(wma_outbuf); | |
| 426 if(pkt.data) av_free_packet(&pkt); | |
| 427 if(c) avcodec_close(c); | |
| 428 if(ic) av_close_input_file(ic); | |
| 429 g_static_mutex_unlock(&wma_mutex); | |
| 430 g_thread_exit(NULL); | |
| 431 return(NULL); | |
| 432 } | |
| 433 | |
| 434 static void wma_play_file(InputPlayback *playback) | |
| 435 { | |
| 436 char *filename = playback->filename; | |
| 437 AVCodec *codec; | |
| 438 | |
| 439 if(av_open_input_file(&ic, str_twenty_to_space(filename), NULL, 0, NULL) < 0) return; | |
| 440 | |
| 441 for(wma_idx = 0; wma_idx < ic->nb_streams; wma_idx++) { | |
| 442 c = &ic->streams[wma_idx]->codec; | |
| 443 if(c->codec_type == CODEC_TYPE_AUDIO) break; | |
| 444 } | |
| 445 | |
| 446 av_find_stream_info(ic); | |
| 447 | |
| 448 codec = avcodec_find_decoder(c->codec_id); | |
| 449 | |
| 450 if(!codec) return; | |
| 451 | |
| 452 if(avcodec_open(c, codec) < 0) return; | |
| 453 | |
| 454 wsong_title = get_song_title(ic, filename); | |
| 455 wsong_time = get_song_time(ic); | |
| 456 | |
| 457 if(playback->output->open_audio(FMT_S16_NE, c->sample_rate, c->channels) <= 0) return; | |
| 458 | |
| 459 wma_st_buff = ST_BUFF; | |
| 460 | |
| 461 wma_ip.set_info(wsong_title, wsong_time, c->bit_rate, c->sample_rate, c->channels); | |
| 462 | |
| 463 /* av_malloc() will wrap posix_memalign() if necessary -nenolod */ | |
| 464 wma_s_outbuf = av_malloc(wma_st_buff); | |
| 465 wma_outbuf = av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE); | |
| 466 | |
| 467 wma_seekpos = -1; | |
| 468 wma_decode = 1; | |
| 469 wma_decode_thread = g_thread_create((GThreadFunc)wma_play_loop, playback, TRUE, NULL); | |
| 470 } | |
| 471 | |
| 472 static void wma_stop(InputPlayback *playback) | |
| 473 { | |
| 474 wma_decode = 0; | |
| 475 if(wma_pause) wma_do_pause(playback, 0); | |
| 476 g_thread_join(wma_decode_thread); | |
| 477 playback->output->close_audio(); | |
| 478 } |
