среда, 16 июня 2010 г.

Разгул примеров для программирования..

Действительно, с рапидшары пропал пример для декодирования мр3; поправлю положение, показав еще раз – как использовать библиотеки от ffmpeg для декодирования звукового файла и последующего его кодирования в мр3

Правда я не разбирался никогда с созданием файлов, с наскоку не получилось – поэтому я пишу только мр3 – потому что у файла там структуры никакой – просто фреймы подряд (ну это если тегов нет)

Короче, вот код; не идеальный ни разу, цель то не в этом; а так – работает; пример представляет из себя 2 поля для ввода имени входного и выходного файлов, и кнопки “ДуИт”, обработчик клика которой собственно дальше:

 var
    mp3_in: PAVFormatContext;
    decoder: PAVCodec;
    decoder_ctx: PAVCodecContext;
    encoder: PAVCodec;
    encoder_ctx: PAVCodecContext;
    pkt: TAVPacket;
    samples: PWord;
    buf: pointer;
    fp, nb, ret1, ret2: integer;
    fs: TFileStream;
  begin
    av_register_all; // регистрация форматов, кодеков etc
    try
      // читаем любые аудиофайлы:
      mp3_in := avformat_alloc_context;
   
      av_open_input_file(mp3_in, pansichar(ansistring(edMP3from.Text)), nil, 0, nil);
      av_find_stream_info(mp3_in);
      // но имеем в виду, что это аудиофайл, так что внутри ожидаем только один поток
      if mp3_in.streams [0].codec.codec_type <> CODEC_TYPE_AUDIO then
        raise Exception.Create('wrong file');
   
      decoder_ctx := mp3_in.streams[0].codec;
      // ищем декодер 
      decoder := avcodec_find_decoder(decoder_ctx.codec_id);
      if decoder = nil then
        raise Exception.Create('decoder not found');
      // если нашли - инициализируем
      if avcodec_open(decoder_ctx, decoder) < 0 then
        raise Exception.Create('decoder error');
   
      // хотим сделать мр3 с теми же параметрами, что и во входном файле, но с битрейтом 192 кбпс
     encoder_ctx := avcodec_alloc_context;
     encoder_ctx.codec_type := CODEC_TYPE_AUDIO;
     encoder_ctx.codec_id := CODEC_ID_MP3;
     encoder_ctx.channels := decoder_ctx.channels;
     encoder_ctx.sample_rate := decoder_ctx.sample_rate;
     encoder_ctx.bit_rate := 192000;
     encoder := avcodec_find_encoder(encoder_ctx.codec_id);
     if encoder = nil then
       raise Exception.Create('encoder not found');
     // ищем кодек и инициализируем если есть (а его может и не быть, смотря как ffmpeg собран)
     if avcodec_open(encoder_ctx, encoder) < 0 then
       raise Exception.Create('encoder error');
  
     // поскоку не умею писать файлы ffmpeg-ом, пишу просто все как есть в файл
     // для мр3 (ТОЛЬКО!) прокатит
     fs := TFileStream.Create(edMP3to.Text, fmCreate);
  
     samples := av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE + FF_INPUT_BUFFER_PADDING_SIZE);
     buf := av_malloc(10000); // ну сколько не жалко и логично
  
     while av_read_frame(mp3_in, @pkt) >= 0 do
     begin
       // пока из вх. файла что-то читается - читаем; для видео пакеты будут из разных потоков (видео/звук)
       // но в моем идеальном примере поток только один
       nb := pkt.size;
       // что дальше: считан пакет размером ххх; но не факт, что декодер при распаковке
       // сразу использует все ххх байт - поэтому надо проверять
       while nb > 0 do
       begin
         fp := AVCODEC_MAX_AUDIO_FRAME_SIZE + FF_INPUT_BUFFER_PADDING_SIZE ;
         // неочевидная фишка - перед каждым вызовом надо указать в fp размер буфера, куда распаковываем
         ret1 := avcodec_decode_audio2(decoder_ctx, samples, @fp, pkt.data, pkt.size);
         if ret1 < 0 then
           raise Exception.Create('decoding error');
         // после decode в fp - размер данных декодированных; сделаем из них мр3
         if fp > 0 then
         begin
           // я не знаю, как эта функция определяет, сколько данных надо взять из samples 
           // (где лежит раскодированный звук)
           // но как-то оно работает..
           ret2 := avcodec_encode_audio (encoder_ctx, buf, 10000, samples);
           if ret2 < 0 then
             raise Exception.Create('encoding error');
           // если нет ошибки при кодировании - пишу закодированный звук в файл
           fs.Write(buf^, ret2);
         end;
         dec (nb, ret1);
       end;
       // ну собственно повторять до окончания файла..
  
       av_free_packet(@pkt);
     end;
  
   finally
     av_free(buf);
     fs.Free;
     avcodec_close(encoder_ctx);
     av_free(encoder_ctx);
     av_free(samples);
     avcodec_close(decoder_ctx);
     av_close_input_file(mp3_in);
     av_free(mp3_in);
   end;
 end;

Надо посмотреть, все ли я ресурсы освободил, я в примерах с этим часто не заморачиваюсь; но суть должна быть понятна..

Проверял на dll-ках, собранных из ffmpeg 0.5.2, работает

2 комментария:

  1. Спасибо =) Только не все mp3 прочитывает...

    ОтветитьУдалить
  2. например? я особо не тестил, один файл прогнал и все - но работать должно в принципе
    пример в студию короче..

    ОтветитьУдалить