The OpenNET Project / Index page

[ новости/++ | форум | wiki | теги ]

Преобразование WMA в MP3 или OGG (sound convert mp3 ogg charset patch)


<< Предыдущая ИНДЕКС Поиск в статьях src Установить закладку Перейти на закладку Следующая >>
Ключевые слова: sound, convert, mp3, ogg, charset, patch,  (найти похожие документы)
From: McMCC <http://mcmcc.bat.ru>; Date: Mon, 20 Dec 2004 18:21:07 +0000 (UTC) Subject: Преобразование WMA в MP3 или OGG Оригинал: http://mcmcc.bat.ru/wma2mp3.html Перегоняем WMA в MP3 или OGG. Набралось тут у меня всяких новинок в формате WMA, но мой автомобильный плеер работает только с форматом MP3, подарок понимаете ли, если бы я сам выбирал то взял бы еще с поддержкой WMA, но как говориться - даренному коню в зубы не смотрят... Так вот, захотелось мне всю коллекцию WMA перегнать в MP3, я это раньше делал с помощью ffmpeg, получалось отлично, но только вот тэги приходилось вручную прописывать, тем более тегы WMA практически никто из существующих под линукс приложений, кроме самого ffmpeg, читать не умеет. Сейчас появилось немного свободного времени и я сделал патч для ffmpeg, который делает копирование тегов из одного формата в другой и делает конвертацию в различных кодировках, unicode, utf-8, cp1251 и т.д. Для автоматизации процесса перегона использовать можно что угодно, любой скрипт, потому как ffmpeg не умеет делать этого. Что нового из ключей появилось: -copytag - Указывает ffmpeg'у, что нужно считать тег из входного файла и перенести его в выходной -fcode - Из какой кодировки -tcode - В какую Выглядит это примерно так: ffmpeg -copytag -fcode KOI8-R -tcode CP1251 -i test.wma -ab 192 -f mp3 test.mp3 Почему указано из KOI8-R, потому как патч берет информацию из WMA файла в юникоде и конвертит в кодировку установленной в вашей локали, т.е. у меня koi8-r, у вас может быть utf-8 или еще какая либо другая, поэтому -fcode должен быть таким, какая локаль установлена у вас. Но это работает только с теми форматами которые пишут информацию в юникоде, т.е. ogg тоже попадают под такое правило: ffmpeg -copytag -fcode KOI8-R -tcode CP1251 -i test.ogg -ab 192 -f mp3 test.mp3 У меня плеер не понимает русский, поэтому я перегоняю все в KOI-7, получается что-то наподобии транслита: ffmpeg -copytag -fcode KOI8-R -tcode KOI-7 -i test.wma -ab 192 -f mp3 test.mp3 Вот кусок перегона: ffmpeg -copytag -fcode KOI8-R -tcode KOI-7 -i test.wma -ab 192 -f mp3 test.mp3 Input #0, asf, from 'test.wma': Duration: 00:02:36.9, bitrate: 46 kb/s Stream #0.0: Audio: wmav2, 44100 Hz, stereo, 45 kb/s Title: Холодное пиво Author: Ленинград Album: Мой друг музыкант Year: 2002 Copyright: Самый Неофициальный Сайт Группы Ленинград и Сергея Шнурова Comments: Только для ознакомления! Output #0, mp3, to 'test.mp3': Stream #0.0: Audio: mp3, 44100 Hz, stereo, 192 kb/s Stream mapping: Stream #0.0 -> #0.0 Press [q] to stop encoding size= 2188kB time=93.4 bitrate= 192.0kbits/s Теперь как это выглядит в mpg123 Title : hOLODNOE PIWO Artist: lENINGRAD Album : mOJ DRUG MUZYKANT Year : 2002 Comment: tOLXKO DLQ OZNAKOMLENIQ! Genre : Blues MPEG 1.0, Layer: III, Freq: 44100, mode: Joint-Stereo, modext: 2, BPF: 626 Channels: 2, copyright: No, original: Yes, CRC: No, emphasis: 0. Bitrate: 192 Kbits/s, Extension value: 0 Audio: 1:1 conversion, rate: 44100, encoding: signed 16 bit, channels: 2 Понятно, что не очень красиво, однако моему плееру всеравно, он все теги показывает в верхнем регистре... Пропатченный ffmpeg можно взять тут: http://mcmcc.bat.ru/myprogs/ffmpeg-0.4.8cvs-060204.tar.bz2 Если интересны изменения которые я делал то можете взять патч: http://mcmcc.bat.ru/mypatches/ffmpeg_tag_mc1.patch И мой маленький скриптик на perl'е, который перегоняет WMA в MP3 с битрейтом 160 kbps сохраняя теги: http://mcmcc.bat.ru/mypatches/wma2mp3.pl P.S. Набирайте ключи для ffmpeg в том порядке, как я указывал в примерах!!! Помимо добавления работы с тегами мне пришлось еще править правильность считывания этих тегов из ogg и wma, плюс добавлена возможность указывать информацию для тегов в ffmpeg, она была раньше, но сильно урезанная,полный список ключей вы получите после запуска ffmpeg'а. На тему показа информации доработан и ffplay, все ключи тоже можно посмотреть после его запуска. Собирать следует с LAME для работы с MP3, внутренний кодек в ffmpeg не очень, скачать можно с моего сайта на страничке http://mcmcc.bat.ru/fedora Перед сборкой надо выполнить configure: ./configure --prefix=/usr --enable-mp3lame --enable-vorbis Если еще что то надо, то посмотрите в хелпе configure... McMCC (11.02.2004 19:29:55)
wma2mp3.pl #!/usr/bin/perl if (($ARGV[0] eq "") || ($ARGV[1] eq "")) { printf("\n\nUse wma2mp3 <in_wma_dir> <out_mp3_dir>\n\n"); exit; } opendir(DH, $ARGV[0]) or die "Couldn't open $ARGV[0] for reading: $!"; @files = grep {/\.wma$/i} readdir (DH); closedir(DH); for $filez (@files) { $file = $filez; $file =~ s/.wma$/.mp3/gi; `ffmpeg -copytag -i "$ARGV[0]/$filez" -ab 160 -f mp3 "$ARGV[1]/$file"`; #print "$filez $file\n"; }
ffmpeg_tag_mc1.patch diff -rupN ffmpeg.orig/ffmpeg.c ffmpeg/ffmpeg.c --- ffmpeg.orig/ffmpeg.c 2004-02-04 18:49:55.000000000 +0300 +++ ffmpeg/ffmpeg.c 2004-02-09 17:51:42.000000000 +0300 @@ -28,6 +28,7 @@ #include <termios.h> #include <sys/resource.h> #include <signal.h> +#include <iconv.h> #endif #ifdef CONFIG_OS2 #include <sys/types.h> @@ -157,10 +158,27 @@ static int audio_codec_id = CODEC_ID_NON static int64_t recording_time = 0; static int64_t start_time = 0; static int file_overwrite = 0; +static char *str_track = NULL; +static char *str_genre = NULL; +static char *str_album = NULL; +static char *str_year = NULL; static char *str_title = NULL; static char *str_author = NULL; static char *str_copyright = NULL; static char *str_comment = NULL; +static char *str_fcode = NULL; +static char *str_tcode = NULL; + +static int free_track; +static int free_genre; +static int free_album; +static int free_year; +static int free_title; +static int free_author; +static int free_copyright; +static int free_comment; + +static int do_ctag = 0; static int do_benchmark = 0; static int do_hex_dump = 0; static int do_pkt_dump = 0; @@ -2147,6 +2165,147 @@ static void opt_start_time(const char *a start_time = parse_date(arg, 1); } +static char *getlocale() +{ + char *str; + + str = strstr(getenv("LANG"), "."); + if(str) + *str++; + else + str = NULL; + + return str; +} + +static void tag_recode(char *before, int len, char *tocode, char *fromcode) +{ + int result; + iconv_t frt; + char ansb[len]; + char ansa[len]; + char *ansbptr = ansb; + char *ansaptr = ansa; + int len1 = 2 * len; + int length = len; + + strncpy(ansb, before, len); + frt = iconv_open(tocode, fromcode); + if (frt == (iconv_t) - 1) + { + fprintf(stderr,"Error iconv_open()!\n"); + return; + } + result = iconv(frt, &ansbptr, &len, &ansaptr, &len1); + if (result == (size_t) - 1) + { + fprintf(stderr,"Error iconv()!\n"); + return; + } + else + strncpy(before, ansa, length); + if (iconv_close(frt) != 0) + if (iconv_close(frt) != 0) + fprintf(stderr,"Error iconv_close()!\n"); + return; +} + +static void dump_stream_info(AVFormatContext *s) +{ + char *slocale; + + slocale = getlocale(); + + if(str_tcode && str_fcode && slocale) + { + if ((s->title[0] != '\0') && !str_title) + tag_recode(s->title, 512, slocale, str_fcode); + if ((s->author[0] != '\0') && !str_author) + tag_recode(s->author, 512, slocale, str_fcode); + if ((s->album[0] != '\0') && !str_album) + tag_recode(s->album, 512, slocale, str_fcode); + if ((s->copyright[0] != '\0') && !str_copyright) + tag_recode(s->copyright, 512, slocale, str_fcode); + if ((s->comment[0] != '\0') && !str_comment) + tag_recode(s->comment, 512, slocale, str_fcode); + } + + if (!str_year && s->year){ + free_year = 1; + str_year = (char*)av_malloc(4); + sprintf(str_year,"%d",s->year); + } + if (!str_track && s->track){ + free_track = 1; + str_track = (char*)av_malloc(4); + sprintf(str_track,"%d",s->track); + } + if (!str_album && s->album){ + free_album = 1; + str_album = (char*)av_malloc(512); + strcpy(str_album, s->album); + } + if (!str_genre && s->genre){ + free_genre = 1; + str_genre = (char*)av_malloc(32); + strcpy(str_genre, s->genre); + } + if (!str_title && s->title){ + free_title = 1; + str_title = (char*)av_malloc(512); + strcpy(str_title, s->title); + } + if (!str_author && s->author){ + free_author = 1; + str_author = (char*)av_malloc(512); + strcpy(str_author, s->author); + } + if (!str_copyright && s->copyright){ + free_copyright = 1; + str_copyright = (char*)av_malloc(512); + strcpy(str_copyright, s->copyright); + } + if (!str_comment && s->comment){ + free_comment = 1; + str_comment = (char*)av_malloc(512); + strcpy(str_comment, s->comment); + } + + if (str_title[0] != '\0') + fprintf(stderr, "Title: %s\n", str_title); + if (str_author[0] != '\0') + fprintf(stderr, "Author: %s\n", str_author); + if (str_album[0] != '\0') + fprintf(stderr, "Album: %s\n", str_album); + if (str_year != 0) + fprintf(stderr, "Year: %s\n", str_year); + if (str_track != 0) + fprintf(stderr, "Track: %s\n", str_track); + if (str_genre[0] != '\0') + fprintf(stderr, "Genre: %s\n", str_genre); + if (str_copyright[0] != '\0') + fprintf(stderr, "Copyright: %s\n", str_copyright); + if (str_comment[0] != '\0') + fprintf(stderr, "Comments: %s\n", str_comment); + +} + +static int last_char(char *str, int len) +{ + int i; + + for(i=len-1; i >= 0; i--) + { + if(str[i] != ' ') + { i++; + break; + } + } + if(i<0) + i=0; + return i; +} + static void opt_input_file(const char *filename) { AVFormatContext *ic; @@ -2247,8 +2406,18 @@ static void opt_input_file(const char *f } input_files[nb_input_files] = ic; + free_track = 0; + free_genre = 0; + free_album = 0; + free_year = 0; + free_title = 0; + free_author = 0; + free_copyright = 0; + free_comment = 0; /* dump the file content */ dump_format(ic, nb_input_files, filename, 0); + if(do_ctag) + dump_stream_info(ic); nb_input_files++; file_iformat = NULL; file_oformat = NULL; @@ -2291,6 +2460,9 @@ static void opt_output_file(const char * int use_video, use_audio, nb_streams, input_has_video, input_has_audio; int codec_id; AVFormatParameters params, *ap = &params; + char *slocale; + + slocale = getlocale(); if (!strcmp(filename, "-")) filename = "pipe:"; @@ -2561,14 +2733,71 @@ static void opt_output_file(const char * exit(1); } - if (str_title) + if (str_year) { + oc->year = atoi(str_year); + if(free_year) + av_free(str_year); + } + if (str_track) { + oc->track = atoi(str_track); + if(free_track) + av_free(str_track); + } + if (str_album){ + str_album[last_char(str_album, strlen(str_album))] = '\0'; + pstrcpy(oc->album, sizeof(oc->album), str_album); + if(str_tcode && str_fcode && slocale) + tag_recode(oc->album, 512, str_tcode, slocale); + if(free_album) + av_free(str_album); + } + if (str_genre){ + str_genre[last_char(str_genre, strlen(str_genre))] = '\0'; + pstrcpy(oc->genre, sizeof(oc->genre), str_genre); + if(free_genre) + av_free(str_genre); + } + if (str_title){ + str_title[last_char(str_title, strlen(str_title))] = '\0'; pstrcpy(oc->title, sizeof(oc->title), str_title); - if (str_author) + if(str_tcode && str_fcode && slocale) + tag_recode(oc->title, 512, str_tcode, slocale); + if(free_title) + av_free(str_title); + } + if (str_author){ + str_author[last_char(str_author, strlen(str_author))] = '\0'; pstrcpy(oc->author, sizeof(oc->author), str_author); - if (str_copyright) + if(str_tcode && str_fcode && slocale) + tag_recode(oc->author, 512, str_tcode, slocale); + if(free_author) + av_free(str_author); + } + if (str_copyright){ + str_copyright[last_char(str_copyright, strlen(str_copyright))] = '\0'; pstrcpy(oc->copyright, sizeof(oc->copyright), str_copyright); - if (str_comment) + if(str_tcode && str_fcode && slocale) + tag_recode(oc->copyright, 512, str_tcode, slocale); + if(free_copyright) + av_free(str_copyright); + } + if (str_comment){ + str_comment[last_char(str_comment, strlen(str_comment))] = '\0'; pstrcpy(oc->comment, sizeof(oc->comment), str_comment); + if(str_tcode && str_fcode && slocale) + tag_recode(oc->comment, 512, str_tcode, slocale); + if(free_comment) + av_free(str_comment); + } + free_year = 0; + free_track = 0; + free_genre = 0; + free_album = 0; + free_year = 0; + free_title = 0; + free_author = 0; + free_copyright = 0; + free_comment = 0; } output_files[nb_output_files++] = oc; @@ -2981,6 +3210,13 @@ const OptionDef options[] = { { "map", HAS_ARG | OPT_EXPERT, {(void*)opt_map}, "set input stream mapping", "file:stream" }, { "t", HAS_ARG, {(void*)opt_recording_time}, "set the recording time", "duration" }, { "ss", HAS_ARG, {(void*)opt_start_time}, "set the start time offset", "time_off" }, + { "copytag", OPT_BOOL, {(void*)&do_ctag}, "copy tag info from input file to output file"}, + { "fcode", HAS_ARG | OPT_STRING, {(void*)&str_fcode}, "set from codepage(CP1251, UTF-8, ...)", "codepage" }, + { "tcode", HAS_ARG | OPT_STRING, {(void*)&str_tcode}, "set to codepage(KOI8-R, UTF-8, ...)", "codepage" }, + { "track", HAS_ARG | OPT_STRING, {(void*)&str_track}, "set the track", "num" }, + { "year", HAS_ARG | OPT_STRING, {(void*)&str_year}, "set the year", "year" }, + { "album", HAS_ARG | OPT_STRING, {(void*)&str_album}, "set the album", "string" }, + { "genre", HAS_ARG | OPT_STRING, {(void*)&str_genre}, "set the genre", "string" }, { "title", HAS_ARG | OPT_STRING, {(void*)&str_title}, "set the title", "string" }, { "author", HAS_ARG | OPT_STRING, {(void*)&str_author}, "set the author", "string" }, { "copyright", HAS_ARG | OPT_STRING, {(void*)&str_copyright}, "set the copyright", "string" }, diff -rupN ffmpeg.orig/ffplay.c ffmpeg/ffplay.c --- ffmpeg.orig/ffplay.c 2004-01-14 23:22:11.000000000 +0300 +++ ffmpeg/ffplay.c 2004-02-09 18:30:30.000000000 +0300 @@ -20,6 +20,7 @@ #include "avformat.h" #include "cmdutils.h" +#include "iconv.h" #include <SDL.h> #include <SDL_thread.h> @@ -179,6 +180,52 @@ static int64_t audio_callback_time; #define FF_QUIT_EVENT (SDL_USEREVENT + 2) SDL_Surface *screen; +static char *str_fcode = NULL; + +static char *getlocale() +{ + char *str; + + str = strstr(getenv("LANG"), "."); + if(str) + *str++; + else + str = NULL; + + return str; +} + +static void tag_recode(char *before, int len, char *fromcode) +{ + int result; + iconv_t frt; + char ansb[len]; + char ansa[len]; + char *ansbptr = ansb; + char *ansaptr = ansa; + int len1 = 2 * len; + int length = len; + + strncpy(ansb, before, len); + frt = iconv_open(getlocale(), fromcode); + if (frt == (iconv_t) - 1) + { + fprintf(stderr,"Error iconv_open()!\n"); + return; + } + result = iconv(frt, &ansbptr, &len, &ansaptr, &len1); + if (result == (size_t) - 1) + { + fprintf(stderr,"Error iconv()!\n"); + return; + } + else + strncpy(before, ansa, length); + if (iconv_close(frt) != 0) + if (iconv_close(frt) != 0) + fprintf(stderr,"Error iconv_close()!\n"); + return; +} /* packet queue handling */ static void packet_queue_init(PacketQueue *q) @@ -1255,6 +1302,22 @@ static void stream_component_close(Video void dump_stream_info(AVFormatContext *s) { + + if(str_fcode) + { + if (s->title[0] != '\0') + tag_recode(s->title, 512, str_fcode); + if (s->author[0] != '\0') + tag_recode(s->author, 512, str_fcode); + if (s->album[0] != '\0') + tag_recode(s->album, 512, str_fcode); + if (s->copyright[0] != '\0') + tag_recode(s->copyright, 512, str_fcode); + if (s->comment[0] != '\0') + tag_recode(s->comment, 512, str_fcode); + } + + if (s->track != 0) fprintf(stderr, "Track: %d\n", s->track); if (s->title[0] != '\0') @@ -1267,6 +1330,10 @@ void dump_stream_info(AVFormatContext *s fprintf(stderr, "Year: %d\n", s->year); if (s->genre[0] != '\0') fprintf(stderr, "Genre: %s\n", s->genre); + if (s->comment[0] != '\0') + fprintf(stderr, "Comment: %s\n", s->comment); + if (s->copyright[0] != '\0') + fprintf(stderr, "Copyright: %s\n", s->copyright); } /* since we have only one decoding thread, we can use a global @@ -1815,6 +1882,7 @@ const OptionDef options[] = { { "rtp_tcp", OPT_EXPERT, {(void*)&opt_rtp_tcp}, "force RTP/TCP protocol usage", "" }, #endif { "sync", HAS_ARG | OPT_EXPERT, {(void*)&opt_sync}, "set audio-video sync. type (type=audio/video/ext)", "type" }, + { "fcode", HAS_ARG | OPT_STRING, {(void*)&str_fcode}, "set from codepage(CP1251, UTF-8, ...)", "codepage" }, { NULL, }, }; diff -rupN ffmpeg.orig/libavformat/asf.c ffmpeg/libavformat/asf.c --- ffmpeg.orig/libavformat/asf.c 2004-01-17 23:26:44.000000000 +0300 +++ ffmpeg/libavformat/asf.c 2004-02-09 17:48:23.000000000 +0300 @@ -19,6 +19,7 @@ #include "avformat.h" #include "avi.h" #include "mpegaudio.h" +#include <iconv.h> #undef NDEBUG #include <assert.h> @@ -741,19 +742,63 @@ static void get_str16(ByteIOContext *pb, } #endif +static char *getlocale() +{ + char *str; + + str = strstr(getenv("LANG"), "."); + if(str) + *str++; + else + str = NULL; + + return str; +} + +static void tag_recode(char *before, int len) +{ + int result; + iconv_t frt; + char ansb[len]; + char ansa[len]; + char *ansbptr = ansb; + char *ansaptr = ansa; + int len1 = 2 * len; + int length = len; + + memcpy(ansb, before, len); + frt = iconv_open(getlocale(), "UNICODE"); + if (frt == (iconv_t) - 1) + { + return; + } + result = iconv(frt, &ansbptr, &len, &ansaptr, &len1); + if (result == (size_t) - 1) + { + return; + } + else + memcpy(before, ansa, length); + if (iconv_close(frt) != 0) + if (iconv_close(frt) != 0) + return; + return; +} + static void get_str16_nolen(ByteIOContext *pb, int len, char *buf, int buf_size) { - int c; + int c, lenz; char *q; q = buf; + lenz = len; while (len > 0) { - c = get_le16(pb); - if ((q - buf) < buf_size - 1) + c = get_byte(pb); + if ((q - buf) < buf_size-1) *q++ = c; - len-=2; + len--; } - *q = '\0'; + tag_recode(buf, lenz); } static int asf_probe(AVProbeData *pd) @@ -976,6 +1021,7 @@ static int asf_read_header(AVFormatConte value = (char *)av_mallocz(value_len); get_str16_nolen(pb, value_len, value, value_len); if (strcmp(name,"WM/AlbumTitle")==0) { strcpy(s->album, value); } + if (strcmp(name,"WM/Year")==0) s->year = atoi(value); av_free(value); } if ((value_type >= 2) || (value_type <= 5)) // boolean or DWORD or QWORD or WORD diff -rupN ffmpeg.orig/libavformat/ogg.c ffmpeg/libavformat/ogg.c --- ffmpeg.orig/libavformat/ogg.c 2003-12-08 20:50:38.000000000 +0300 +++ ffmpeg/libavformat/ogg.c 2004-02-09 11:27:03.000000000 +0300 @@ -41,6 +41,7 @@ static int ogg_write_header(AVFormatCont vorbis_block vb ; ogg_packet header, header_comm, header_code ; int n ; + char track[4], year[4]; &header_comm, &header_code) ; srand(time(NULL)); ogg_stream_init(&context->os, rand()); @@ -64,8 +65,28 @@ static int ogg_write_header(AVFormatCont vorbis_comment_init(&vc) ; vorbis_comment_add_tag(&vc, "encoder", LIBAVFORMAT_IDENT) ; - if(*avfcontext->title) + if(avfcontext->title) vorbis_comment_add_tag(&vc, "title", avfcontext->title) ; + if(avfcontext->album) + vorbis_comment_add_tag(&vc, "album", avfcontext->album) ; + if(avfcontext->author) + vorbis_comment_add_tag(&vc, "artist", avfcontext->author) ; + if(avfcontext->genre) + vorbis_comment_add_tag(&vc, "genre", avfcontext->genre) ; + if(avfcontext->comment) + vorbis_comment_add_tag(&vc, "comment", avfcontext->comment) ; + if(avfcontext->copyright) + vorbis_comment_add_tag(&vc, "copyright", avfcontext->copyright) ; + if(avfcontext->year) + { + sprintf(year, "%d", avfcontext->year); + vorbis_comment_add_tag(&vc, "date", year) ; + } + if(avfcontext->track) + { + sprintf(track, "%d", avfcontext->track); + vorbis_comment_add_tag(&vc, "tracknumber", track) ; + } vorbis_analysis_headerout(&vd, &vc, &header, &header_comm, &header_code) ;

<< Предыдущая ИНДЕКС Поиск в статьях src Установить закладку Перейти на закладку Следующая >>

Обсуждение [ RSS ]
 
  • 1, Мдя...., 00:45, 16/10/2009 [ответить] [смотреть все]
  • +/
    А теперь просто берем Audio Transcoder (http://www.audio-transcoder.com) и конвертим все в пару кликов, с переносом тегов и все такое ;)
     
     
  • 2, my_name, 12:47, 19/12/2010 [^] [ответить] [смотреть все]
  • +/
    Довольно глупое замечание. Учитывая, что audio transcoder - платная виндовая программа.
     

    Ваш комментарий
    Имя:         
    E-Mail:      
    Заголовок:
    Текст:





      Закладки на сайте
      Проследить за страницей
    Created 1996-2017 by Maxim Chirkov  
    ДобавитьРекламаВебмастеруГИД  
    Hosting by Ihor