--- /dev/null
+
+/*
+ * CINELERRA
+ * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <limits.h>
+// work around (centos) for __STDC_CONSTANT_MACROS
+#include <lzma.h>
+#ifndef INT64_MAX
+# define INT64_MAX 9223372036854775807LL
+#endif
+
+extern "C"
+{
+#include "libavcodec/avcodec.h"
+}
+
+#include "asset.h"
+#include "clip.h"
+#include "fileac3.h"
+#include "file.h"
+#include "filempeg.h"
+#include "language.h"
+#include "mainerror.h"
+
+
+
+#include <string.h>
+
+FileAC3::FileAC3(Asset *asset, File *file)
+ : FileBase(asset, file)
+{
+ reset_parameters();
+ mpg_file = 0;
+}
+
+FileAC3::~FileAC3()
+{
+ if( mpg_file ) delete mpg_file;
+ close_file();
+}
+
+int FileAC3::reset_parameters_derived()
+{
+ codec = 0;
+ codec_context = 0;
+ resample_context = 0;
+ fd = 0;
+ temp_raw = 0;
+ temp_raw_size = 0;
+ temp_raw_allocated = 0;
+ temp_compressed = 0;
+ compressed_allocated = 0;
+ return 0;
+}
+
+void FileAC3::get_parameters(BC_WindowBase *parent_window,
+ Asset *asset,
+ BC_WindowBase* &format_window,
+ int audio_options,
+ int video_options)
+{
+ if(audio_options)
+ {
+
+ AC3ConfigAudio *window = new AC3ConfigAudio(parent_window, asset);
+ format_window = window;
+ window->create_objects();
+ window->run_window();
+ delete window;
+ }
+}
+
+int FileAC3::check_sig()
+{
+// Libmpeg3 does this in FileMPEG.
+ return 0;
+}
+
+int64_t FileAC3::get_channel_layout(int channels)
+{
+ switch( channels ) {
+ case 1: return AV_CH_LAYOUT_MONO;
+ case 2: return AV_CH_LAYOUT_STEREO;
+ case 3: return AV_CH_LAYOUT_SURROUND;
+ case 4: return AV_CH_LAYOUT_QUAD;
+ case 5: return AV_CH_LAYOUT_5POINT0;
+ case 6: return AV_CH_LAYOUT_5POINT1;
+ case 8: return AV_CH_LAYOUT_7POINT1;
+ }
+ return 0;
+}
+
+int FileAC3::open_file(int rd, int wr)
+{
+ int result = 0;
+
+ if(rd)
+ {
+ if( !mpg_file )
+ mpg_file = new FileMPEG(file->asset, file);
+ result = mpg_file->open_file(1, 0);
+ if( result ) {
+ eprintf("Error while opening \"%s\" for reading. \n%m\n", asset->path);
+ }
+ }
+
+ if( !result && wr )
+ {
+ //avcodec_init();
+ avcodec_register_all();
+ codec = avcodec_find_encoder(AV_CODEC_ID_AC3);
+ if(!codec)
+ {
+ eprintf("FileAC3::open_file codec not found.\n");
+ result = 1;
+ }
+ if( !result && !(fd = fopen(asset->path, "w")))
+ {
+ eprintf("Error while opening \"%s\" for writing. \n%m\n", asset->path);
+ result = 1;
+ }
+ if( !result ) {
+ int channels = asset->channels;
+ int sample_rate = asset->sample_rate;
+ int64_t layout = get_channel_layout(channels);
+ int bitrate = asset->ac3_bitrate * 1000;
+ codec_context = avcodec_alloc_context3(codec);
+ codec_context->bit_rate = bitrate;
+ codec_context->sample_rate = sample_rate;
+ codec_context->channels = channels;
+ codec_context->channel_layout = layout;
+ codec_context->sample_fmt = codec->sample_fmts[0];
+ resample_context = swr_alloc_set_opts(NULL,
+ layout, codec_context->sample_fmt, sample_rate,
+ layout, AV_SAMPLE_FMT_S16, sample_rate,
+ 0, NULL);
+ swr_init(resample_context);
+ if(avcodec_open2(codec_context, codec, 0))
+ {
+ eprintf("FileAC3::open_file failed to open codec.\n");
+ result = 1;
+ }
+ }
+ }
+
+ return result;
+}
+
+int FileAC3::close_file()
+{
+ if( mpg_file )
+ {
+ delete mpg_file;
+ mpg_file = 0;
+ }
+ if(codec_context)
+ {
+ avcodec_close(codec_context);
+ avcodec_free_context(&codec_context);
+ codec = 0;
+ }
+ if( resample_context )
+ swr_free(&resample_context);
+ if(fd)
+ {
+ fclose(fd);
+ fd = 0;
+ }
+ if(temp_raw)
+ {
+ delete [] temp_raw;
+ temp_raw = 0;
+ }
+ if(temp_compressed)
+ {
+ delete [] temp_compressed;
+ temp_compressed = 0;
+ }
+ reset_parameters();
+ FileBase::close_file();
+ return 0;
+}
+
+int FileAC3::read_samples(double *buffer, int64_t len)
+{
+ return !mpg_file ? 0 : mpg_file->read_samples(buffer, len);
+}
+
+int FileAC3::get_index(char *index_path)
+{
+ return !mpg_file ? 1 : mpg_file->get_index(index_path);
+}
+
+// Channel conversion matrices because ffmpeg encodes a
+// different channel order than liba52 decodes.
+// Each row is an output channel.
+// Each column is an input channel.
+// static int channels5[] =
+// {
+// { }
+// };
+//
+// static int channels6[] =
+// {
+// { }
+// };
+
+
+int FileAC3::write_samples(double **buffer, int64_t len)
+{
+// Convert buffer to encoder format
+ if(temp_raw_size + len > temp_raw_allocated)
+ {
+ int new_allocated = temp_raw_size + len;
+ int16_t *new_raw = new int16_t[new_allocated * asset->channels];
+ if(temp_raw)
+ {
+ memcpy(new_raw,
+ temp_raw,
+ sizeof(int16_t) * temp_raw_size * asset->channels);
+ delete [] temp_raw;
+ }
+ temp_raw = new_raw;
+ temp_raw_allocated = new_allocated;
+ }
+
+// Allocate compressed data buffer
+ if(temp_raw_allocated * asset->channels * 2 > compressed_allocated)
+ {
+ compressed_allocated = temp_raw_allocated * asset->channels * 2;
+ delete [] temp_compressed;
+ temp_compressed = new unsigned char[compressed_allocated];
+ }
+
+// Append buffer to temp raw
+ int16_t *out_ptr = temp_raw + temp_raw_size * asset->channels;
+ for(int i = 0; i < len; i++)
+ {
+ for(int j = 0; j < asset->channels; j++)
+ {
+ int sample = (int)(buffer[j][i] * 32767);
+ CLAMP(sample, -32768, 32767);
+ *out_ptr++ = sample;
+ }
+ }
+ temp_raw_size += len;
+
+ AVCodecContext *&avctx = codec_context;
+ int frame_size = avctx->frame_size;
+ int output_size = 0, cur_sample = 0, ret = 0;
+ for(cur_sample = 0; !ret &&
+ cur_sample + frame_size <= temp_raw_size;
+ cur_sample += frame_size)
+ {
+ AVPacket avpkt;
+ av_init_packet(&avpkt);
+ avpkt.data = temp_compressed + output_size;
+ avpkt.size = compressed_allocated - output_size;
+ AVFrame *frame = av_frame_alloc();
+ frame->nb_samples = frame_size;
+ frame->format = avctx->sample_fmt;
+ frame->channel_layout = avctx->channel_layout;
+ frame->sample_rate = avctx->sample_rate;
+ ret = av_frame_get_buffer(frame, 0);
+ if( ret >= 0 ) {
+ const uint8_t *samples = (uint8_t *)temp_raw +
+ cur_sample * sizeof(int16_t) * asset->channels;
+ ret = swr_convert(resample_context,
+ (uint8_t **)frame->extended_data, frame_size,
+ &samples, frame_size);
+ }
+ if( ret >= 0 ) {
+ frame->pts = avctx->sample_rate && avctx->time_base.num ?
+ file->get_audio_position() : AV_NOPTS_VALUE ;
+ int got_packet = 0;
+ ret = avcodec_encode_audio2(avctx, &avpkt, frame, &got_packet);
+ if( ret < 0 ) {
+ char errmsg[BCSTRLEN];
+ av_strerror(ret, errmsg, sizeof(errmsg));
+ fprintf(stderr, "avcodec_encode_audio2 failed. \n%s\n", errmsg);
+ }
+ }
+ av_packet_free_side_data(&avpkt);
+ output_size += avpkt.size;
+ if(frame->extended_data != frame->data)
+ av_freep(&frame->extended_data);
+ av_frame_free(&frame);
+ }
+
+// Shift buffer back
+ memcpy(temp_raw,
+ temp_raw + cur_sample * asset->channels,
+ (temp_raw_size - cur_sample) * sizeof(int16_t) * asset->channels);
+ temp_raw_size -= cur_sample;
+
+ int bytes_written = fwrite(temp_compressed, 1, output_size, fd);
+ if(bytes_written < output_size)
+ {
+ eprintf("Error while writing samples. \n%m\n");
+ return 1;
+ }
+ return 0;
+}
+
+
+
+
+
+
+
+AC3ConfigAudio::AC3ConfigAudio(BC_WindowBase *parent_window,
+ Asset *asset)
+ : BC_Window(PROGRAM_NAME ": Audio Compression",
+ parent_window->get_abs_cursor_x(1),
+ parent_window->get_abs_cursor_y(1),
+ 500,
+ BC_OKButton::calculate_h() + 100,
+ 500,
+ BC_OKButton::calculate_h() + 100,
+ 0,
+ 0,
+ 1)
+{
+ this->parent_window = parent_window;
+ this->asset = asset;
+}
+
+void AC3ConfigAudio::create_objects()
+{
+ int x = 10, y = 10;
+ int x1 = 150;
+ lock_window("AC3ConfigAudio::create_objects");
+ add_tool(new BC_Title(x, y, "Bitrate (kbps):"));
+ AC3ConfigAudioBitrate *bitrate;
+ add_tool(bitrate =
+ new AC3ConfigAudioBitrate(this,
+ x1,
+ y));
+ bitrate->create_objects();
+
+ add_subwindow(new BC_OKButton(this));
+ show_window(1);
+ unlock_window();
+}
+
+int AC3ConfigAudio::close_event()
+{
+ set_done(0);
+ return 1;
+}
+
+
+
+
+
+
+AC3ConfigAudioBitrate::AC3ConfigAudioBitrate(AC3ConfigAudio *gui,
+ int x,
+ int y)
+ : BC_PopupMenu(x,
+ y,
+ 150,
+ AC3ConfigAudioBitrate::bitrate_to_string(gui->string, gui->asset->ac3_bitrate))
+{
+ this->gui = gui;
+}
+
+char* AC3ConfigAudioBitrate::bitrate_to_string(char *string, int bitrate)
+{
+ sprintf(string, "%d", bitrate);
+ return string;
+}
+
+void AC3ConfigAudioBitrate::create_objects()
+{
+ add_item(new BC_MenuItem("32"));
+ add_item(new BC_MenuItem("40"));
+ add_item(new BC_MenuItem("48"));
+ add_item(new BC_MenuItem("56"));
+ add_item(new BC_MenuItem("64"));
+ add_item(new BC_MenuItem("80"));
+ add_item(new BC_MenuItem("96"));
+ add_item(new BC_MenuItem("112"));
+ add_item(new BC_MenuItem("128"));
+ add_item(new BC_MenuItem("160"));
+ add_item(new BC_MenuItem("192"));
+ add_item(new BC_MenuItem("224"));
+ add_item(new BC_MenuItem("256"));
+ add_item(new BC_MenuItem("320"));
+ add_item(new BC_MenuItem("384"));
+ add_item(new BC_MenuItem("448"));
+ add_item(new BC_MenuItem("512"));
+ add_item(new BC_MenuItem("576"));
+ add_item(new BC_MenuItem("640"));
+}
+
+int AC3ConfigAudioBitrate::handle_event()
+{
+ gui->asset->ac3_bitrate = atol(get_text());
+ return 1;
+}
+
+
+