Mercurial > audlegacy-plugins
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ffmpeg/ffmpeg.c Mon Mar 12 13:00:06 2007 -0700 @@ -0,0 +1,478 @@ +/* + * Audacious WMA input plugin + * (C) 2005 Audacious development team + * + * Based on: + * xmms-wma - WMA player for BMP + * Copyright (C) 2004,2005 McMCC <mcmcc@mail.ru> + * bmp-wma - WMA player for BMP + * Copyright (C) 2004 Roman Bogorodskiy <bogorodskiy@inbox.ru> + * + * 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. + */ +#define _XOPEN_SOURCE 600 +#include <stdlib.h> +#include <unistd.h> +#include <math.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <glib.h> + +#include <audacious/plugin.h> +#include <audacious/output.h> +#include <audacious/util.h> +#include <audacious/titlestring.h> +#include <audacious/vfs.h> +#include <audacious/strings.h> +#include <audacious/i18n.h> + +#include "avcodec.h" +#include "avformat.h" + +#define ABOUT_TXT "Adapted for use in audacious by Tony Vroon (chainsaw@gentoo.org) from\n \ +the BEEP-WMA plugin which is Copyright (C) 2004,2005 Mokrushin I.V. aka McMCC (mcmcc@mail.ru)\n \ +and the BMP-WMA plugin which is Copyright (C) 2004 Roman Bogorodskiy <bogorodskiy@inbox.ru>.\n \ +This plugin based on source code " LIBAVCODEC_IDENT "\nby Fabrice Bellard from \ +http://ffmpeg.sourceforge.net.\n\n \ +This program is free software; you can redistribute it and/or modify \n \ +it under the terms of the GNU General Public License as published by \n \ +the Free Software Foundation; either version 2 of the License, or \n \ +(at your option) any later version. \n\n \ +This program is distributed in the hope that it will be useful, \n \ +but WITHOUT ANY WARRANTY; without even the implied warranty of \n \ +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. \n \ +See the GNU General Public License for more details.\n" +#define PLUGIN_NAME "Audacious-WMA" +#define PLUGIN_VERSION "v.1.0.5" +#define ST_BUFF 1024 + +static int wma_decode = 0; +static gboolean wma_pause = 0; +static int wma_seekpos = -1; +static int wma_st_buff, wma_idx, wma_idx2; +static GThread *wma_decode_thread; +GStaticMutex wma_mutex = G_STATIC_MUTEX_INIT; +static AVCodecContext *c = NULL; +static AVFormatContext *ic = NULL; +static AVCodecContext *c2 = NULL; +static AVFormatContext *ic2 = NULL; +static uint8_t *wma_outbuf, *wma_s_outbuf; + +char description[64]; +static void wma_about(void); +static void wma_init(void); +static int wma_is_our_file(char *filename); +static int wma_is_our_fd(char *filename, VFSFile *fd); +static void wma_play_file(InputPlayback *data); +static void wma_stop(InputPlayback *data); +static void wma_seek(InputPlayback *data, int time); +static void wma_do_pause(InputPlayback *data, short p); +static int wma_get_time(InputPlayback *data); +static void wma_get_song_info(char *filename, char **title, int *length); +static TitleInput *wma_get_song_tuple(char *filename); +static char *wsong_title; +static int wsong_time; + +static GtkWidget *dialog1, *button1, *label1; + +InputPlugin *get_iplugin_info(void); + +gchar *wma_fmts[] = { "wma", NULL }; + +InputPlugin wma_ip = +{ + NULL, // Filled in by xmms + NULL, // Filled in by xmms + description, // The description that is shown in the preferences box + wma_init, // Called when the plugin is loaded + wma_about, // Show the about box + NULL, // Show the configure box + wma_is_our_file, // Return 1 if the plugin can handle the file + NULL, // Scan dir + wma_play_file, // Play file + wma_stop, // Stop + wma_do_pause, // Pause + wma_seek, // Seek + NULL, // Set the equalizer, most plugins won't be able to do this + wma_get_time, // Get the time, usually returns the output plugins output time + NULL, // Get volume + NULL, // Set volume + NULL, // OBSOLETE! + NULL, // OBSOLETE! + NULL, // Send data to the visualization plugins + NULL, // Fill in the stuff that is shown in the player window + NULL, // Show some text in the song title box. Filled in by xmms + wma_get_song_info, // Function to grab the title string + NULL, // Bring up an info window for the filename passed in + NULL, // Handle to the current output plugin. Filled in by xmms + wma_get_song_tuple, // Tuple builder + NULL, + NULL, + wma_is_our_fd, // vfs + wma_fmts +}; + +InputPlugin *get_iplugin_info(void) +{ + memset(description, 0, 64); + wma_ip.description = g_strdup_printf(_("WMA Player %s"), PACKAGE_VERSION); + return &wma_ip; +} + +static gchar *str_twenty_to_space(gchar * str) +{ + gchar *match, *match_end; + + g_return_val_if_fail(str != NULL, NULL); + + while ((match = strstr(str, "%20"))) { + match_end = match + 3; + *match++ = ' '; + while (*match_end) + *match++ = *match_end++; + *match = 0; + } + + return str; +} + +static void wma_about(void) +{ + char *title; + char *message; + + if (dialog1) return; + + title = (char *)g_malloc(80); + message = (char *)g_malloc(1000); + memset(title, 0, 80); + memset(message, 0, 1000); + + sprintf(title, _("About %s"), PLUGIN_NAME); + sprintf(message, "%s %s\n\n%s", PLUGIN_NAME, PLUGIN_VERSION, ABOUT_TXT); + + dialog1 = gtk_dialog_new(); + g_signal_connect(G_OBJECT(dialog1), "destroy", + G_CALLBACK(gtk_widget_destroyed), &dialog1); + gtk_window_set_title(GTK_WINDOW(dialog1), title); + gtk_window_set_policy(GTK_WINDOW(dialog1), FALSE, FALSE, FALSE); + gtk_container_border_width(GTK_CONTAINER(dialog1), 5); + label1 = gtk_label_new(message); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog1)->vbox), label1, TRUE, TRUE, 0); + gtk_widget_show(label1); + + button1 = gtk_button_new_with_label(_(" Close ")); + g_signal_connect_swapped(G_OBJECT(button1), "clicked", + G_CALLBACK(gtk_widget_destroy), + GTK_OBJECT(dialog1)); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog1)->action_area), button1, + FALSE, FALSE, 0); + + gtk_widget_show(button1); + gtk_widget_show(dialog1); + gtk_widget_grab_focus(button1); + g_free(title); + g_free(message); +} + +static void wma_init(void) +{ + avcodec_init(); + avcodec_register_all(); + av_register_all(); +} + +static int wma_is_our_file(char *filename) +{ + AVCodec *codec2; + + if(av_open_input_file(&ic2, str_twenty_to_space(filename), NULL, 0, NULL) < 0) return 0; + + for(wma_idx2 = 0; wma_idx2 < ic2->nb_streams; wma_idx2++) { + c2 = &ic2->streams[wma_idx2]->codec; + if(c2->codec_type == CODEC_TYPE_AUDIO) break; + } + + av_find_stream_info(ic2); + + codec2 = avcodec_find_decoder(c2->codec_id); + + if(!codec2) { + av_close_input_file(ic2); + return 0; + } + + av_close_input_file(ic2); + return 1; +} + +static int wma_is_our_fd(char *filename, VFSFile *fd) +{ + AVCodec *codec2; + + if(av_open_input_vfsfile(&ic2, filename, fd, NULL, 0, NULL) < 0) return 0; + + for(wma_idx2 = 0; wma_idx2 < ic2->nb_streams; wma_idx2++) { + c2 = &ic2->streams[wma_idx2]->codec; + if(c2->codec_type == CODEC_TYPE_AUDIO) break; + } + + av_find_stream_info(ic2); + + codec2 = avcodec_find_decoder(c2->codec_id); + + return 1; +} + +static void wma_do_pause(InputPlayback *playback, short p) +{ + wma_pause = p; + playback->output->pause(wma_pause); +} + +static void wma_seek(InputPlayback *playback, int time) +{ + wma_seekpos = time; + if(wma_pause) playback->output->pause(0); + while(wma_decode && wma_seekpos!=-1) xmms_usleep(10000); + if(wma_pause) playback->output->pause(1); +} + +static int wma_get_time(InputPlayback *playback) +{ + playback->output->buffer_free(); + if(wma_decode) return playback->output->output_time(); + return -1; +} + +static gchar *extname(const char *filename) +{ + gchar *ext = strrchr(filename, '.'); + if(ext != NULL) ++ext; + return ext; +} + +static char* w_getstr(char* str) +{ + if(str && strlen(str) > 0) return g_strdup(str); + return NULL; +} + +static TitleInput *wma_get_song_tuple(gchar * filename) +{ + TitleInput *tuple = NULL; + AVFormatContext *in = NULL; + gchar *filename_proxy = g_strdup(filename); + + if (av_open_input_file(&in, str_twenty_to_space(filename), NULL, 0, NULL) < 0) + return NULL; + + tuple = bmp_title_input_new(); + + tuple->file_name = g_path_get_basename(filename_proxy); + tuple->file_path = g_path_get_dirname(filename_proxy); + tuple->file_ext = extname(filename_proxy); + + av_find_stream_info(in); + + if((in->title[0] != '\0') || (in->author[0] != '\0') || (in->album[0] != '\0') || + (in->comment[0] != '\0') || (in->genre[0] != '\0') || (in->year != 0) || (in->track != 0)) + { + tuple->performer = str_to_utf8(w_getstr(in->author)); + tuple->album_name = str_to_utf8(w_getstr(in->album)); + tuple->track_name = str_to_utf8(w_getstr(in->title)); + tuple->year = in->year; + tuple->track_number = in->track; + tuple->genre = str_to_utf8(w_getstr(in->genre)); + tuple->comment = str_to_utf8(w_getstr(in->comment)); + } + + if (in->duration) + tuple->length = in->duration / 1000; + + av_close_input_file(in); + + return tuple; +} + +static gchar *get_song_title(AVFormatContext *in, gchar * filename) +{ + gchar *ret = NULL; + TitleInput *input; + + input = bmp_title_input_new(); + + if((in->title[0] != '\0') || (in->author[0] != '\0') || (in->album[0] != '\0') || + (in->comment[0] != '\0') || (in->genre[0] != '\0') || (in->year != 0) || (in->track != 0)) + { + input->performer = w_getstr(in->author); + input->album_name = w_getstr(in->album); + input->track_name = w_getstr(in->title); + input->year = in->year; + input->track_number = in->track; + input->genre = w_getstr(in->genre); + input->comment = w_getstr(in->comment); + } + input->file_name = g_path_get_basename(filename); + input->file_path = g_path_get_dirname(filename); + input->file_ext = extname(filename); + ret = xmms_get_titlestring(xmms_get_gentitle_format(), input); + if(input) g_free(input); + + if(!ret) + { + ret = g_strdup(input->file_name); + if (extname(ret) != NULL) + *(extname(ret) - 1) = '\0'; + } + return ret; +} + +static guint get_song_time(AVFormatContext *in) +{ + if(in->duration) + return in->duration/1000; + else + return 0; +} + +static void wma_get_song_info(char *filename, char **title_real, int *len_real) +{ + TitleInput *tuple = wma_get_song_tuple(filename); + + if (tuple == NULL) + return; + + (*len_real) = tuple->length; + (*title_real) = xmms_get_titlestring(xmms_get_gentitle_format(), tuple); +} + +static void wma_playbuff(InputPlayback *playback, int out_size) +{ + FifoBuffer f; + int sst_buff; + + fifo_init(&f, out_size*2); + fifo_write(&f, wma_outbuf, out_size, &f.wptr); + while(!fifo_read(&f, wma_s_outbuf, wma_st_buff, &f.rptr) && wma_decode) + { + sst_buff = wma_st_buff; + if(wma_pause) memset(wma_s_outbuf, 0, sst_buff); + while(playback->output->buffer_free() < wma_st_buff) xmms_usleep(20000); + produce_audio(playback->output->written_time(), FMT_S16_NE, + c->channels, sst_buff, (short *)wma_s_outbuf, NULL); + memset(wma_s_outbuf, 0, sst_buff); + } + fifo_free(&f); + return; +} + +static void *wma_play_loop(void *arg) +{ + InputPlayback *playback = arg; + uint8_t *inbuf_ptr; + int out_size, size, len; + AVPacket pkt; + + g_static_mutex_lock(&wma_mutex); + while(wma_decode){ + + if(wma_seekpos != -1) + { + av_seek_frame(ic, wma_idx, wma_seekpos * 1000000LL); + playback->output->flush(wma_seekpos * 1000); + wma_seekpos = -1; + } + + if(av_read_frame(ic, &pkt) < 0) break; + + size = pkt.size; + inbuf_ptr = pkt.data; + + if(size == 0) break; + + while(size > 0){ + len = avcodec_decode_audio(c, (short *)wma_outbuf, &out_size, + inbuf_ptr, size); + if(len < 0) break; + + if(out_size <= 0) continue; + + wma_playbuff(playback, out_size); + + size -= len; + inbuf_ptr += len; + if(pkt.data) av_free_packet(&pkt); + } + } + while(wma_decode && playback->output->buffer_playing()) xmms_usleep(30000); + wma_decode = 0; + if(wma_s_outbuf) g_free(wma_s_outbuf); + if(wma_outbuf) g_free(wma_outbuf); + if(pkt.data) av_free_packet(&pkt); + if(c) avcodec_close(c); + if(ic) av_close_input_file(ic); + g_static_mutex_unlock(&wma_mutex); + g_thread_exit(NULL); + return(NULL); +} + +static void wma_play_file(InputPlayback *playback) +{ + char *filename = playback->filename; + AVCodec *codec; + + if(av_open_input_file(&ic, str_twenty_to_space(filename), NULL, 0, NULL) < 0) return; + + for(wma_idx = 0; wma_idx < ic->nb_streams; wma_idx++) { + c = &ic->streams[wma_idx]->codec; + if(c->codec_type == CODEC_TYPE_AUDIO) break; + } + + av_find_stream_info(ic); + + codec = avcodec_find_decoder(c->codec_id); + + if(!codec) return; + + if(avcodec_open(c, codec) < 0) return; + + wsong_title = get_song_title(ic, filename); + wsong_time = get_song_time(ic); + + if(playback->output->open_audio(FMT_S16_NE, c->sample_rate, c->channels) <= 0) return; + + wma_st_buff = ST_BUFF; + + wma_ip.set_info(wsong_title, wsong_time, c->bit_rate, c->sample_rate, c->channels); + + /* av_malloc() will wrap posix_memalign() if necessary -nenolod */ + wma_s_outbuf = av_malloc(wma_st_buff); + wma_outbuf = av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE); + + wma_seekpos = -1; + wma_decode = 1; + wma_decode_thread = g_thread_create((GThreadFunc)wma_play_loop, playback, TRUE, NULL); +} + +static void wma_stop(InputPlayback *playback) +{ + wma_decode = 0; + if(wma_pause) wma_do_pause(playback, 0); + g_thread_join(wma_decode_thread); + playback->output->close_audio(); +}
