<commit_before>package com.lisb.android.mediashrink;

import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.media.MediaMuxer;
import android.util.Log;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicReference;

public class AudioShrink {

	private static final String LOG_TAG = AudioShrink.class.getSimpleName();
	private static final boolean VERBOSE = false;

	private static final long TIMEOUT_USEC = 250;
	private static final String CODEC = "audio/mp4a-latm";
	private static final int AAC_DEFAULT_PROFILE = MediaCodecInfo.CodecProfileLevel.AACObjectHE;
	private static final int AAC_SECOND_PROFILE = MediaCodecInfo.CodecProfileLevel.AACObjectLC;
	private int bitRate;

	private final MediaExtractor extractor;
	private final MediaMuxer muxer;
	private final UnrecoverableErrorCallback errorCallback;

	private OnProgressListener onProgressListener;

	private static final long UPDATE_PROGRESS_INTERVAL_MS = 3 * 1000;

	public AudioShrink(MediaExtractor extractor, MediaMuxer muxer,
			UnrecoverableErrorCallback errorCallback) {
		this.extractor = extractor;
		this.muxer = muxer;
		this.errorCallback = errorCallback;
	}

	public void setBitRate(int bitRate) {
		this.bitRate = bitRate;
	}

	public void setOnProgressListener(OnProgressListener onProgressListener) {
		this.onProgressListener = onProgressListener;
	}

	/**
	 * エンコーダの設定に使うフォーマットを作成する。 <br/>
	 * {@link MediaMuxer#addTrack(MediaFormat)} には利用できない。
	 */
	private MediaFormat createEncoderConfigurationFormat(MediaFormat origin) {
		final int channelCount = origin
				.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
		final MediaFormat format = MediaFormat.createAudioFormat(CODEC,
				origin.getInteger(MediaFormat.KEY_SAMPLE_RATE), channelCount);
		// TODO ビットレートが元の値より大きくならないようにする
		format.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);

		Integer profile = null;
		// OMX.google.aac.encoder は HE-AAC プロファイルで mono 音声を扱うと
		// 出力が少しおかしくなりブラウザで再生できなくなる。
		// ( ffprobe で確認したところ、簡易表示ではチャネル数プロパティが stereo、詳細表示では mono になっている )
		if (channelCount == 1) {
			final String mimetype = origin.getString(MediaFormat.KEY_MIME);
			final MediaCodecInfo encoderInfo = Utils
					.selectCodec(mimetype, true);
			if ("OMX.google.aac.encoder".equals(encoderInfo.getName())) {
				profile = AAC_SECOND_PROFILE;
			}
		}
		if (profile == null) {
			profile = AAC_DEFAULT_PROFILE;
		}

		format.setInteger(MediaFormat.KEY_AAC_PROFILE, profile);

		Log.d(LOG_TAG, "create audio encoder configuration format:" + format);

		return format;
	}

	private void reencode(final int trackIndex, final Integer newTrackIndex,
			final ReencodeListener listener) throws DecodeException {
		final MediaFormat currentFormat = extractor.getTrackFormat(trackIndex);
		final MediaFormat encoderConfigurationFormat = createEncoderConfigurationFormat(currentFormat);

		MediaCodec encoder = null;
		MediaCodec decoder = null;

		ByteBuffer[] decoderInputBuffers = null;
		ByteBuffer[] decoderOutputBuffers = null;
		MediaCodec.BufferInfo decoderOutputBufferInfo = null;

		ByteBuffer[] encoderInputBuffers = null;
		ByteBuffer[] encoderOutputBuffers = null;
		MediaCodec.BufferInfo encoderOutputBufferInfo = null;

		// 進捗取得に利用
		final float durationUs = currentFormat
				.getLong(MediaFormat.KEY_DURATION);
		final long startTimeNs = System.nanoTime();
		long deliverProgressCount = 0;

		try {
			// create encoder
			encoder = createEncoder(encoderConfigurationFormat);
			encoder.start();

			encoderInputBuffers = encoder.getInputBuffers();
			encoderOutputBuffers = encoder.getOutputBuffers();
			encoderOutputBufferInfo = new MediaCodec.BufferInfo();

			// create decorder
			decoder = createDecoder(currentFormat);
			if (decoder == null) {
				Log.e(LOG_TAG, "audio decoder not found.");
				throw new DecodeException("audio decoder not found.");<commit_msg>fix:output wrong time_base_codec.<commit_after>package com.lisb.android.mediashrink;

import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.media.MediaMuxer;
import android.util.Log;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicReference;

public class AudioShrink {

	private static final String LOG_TAG = AudioShrink.class.getSimpleName();
	private static final boolean VERBOSE = false;

	private static final long TIMEOUT_USEC = 250;
	private static final String CODEC = "audio/mp4a-latm";
	// Because AACObjectHE of some encoder(ex. OMX.google.aac.encoder) is buggy,
	// Don't use AACObjectHE.
	//
	// bug example:
	// - specify mono sound but output stereo sound.
	// - output wrong time_base_codec.
	private static final int AAC_PROFILE = MediaCodecInfo.CodecProfileLevel.AACObjectLC;
	private int bitRate;

	private final MediaExtractor extractor;
	private final MediaMuxer muxer;
	private final UnrecoverableErrorCallback errorCallback;

	private OnProgressListener onProgressListener;

	private static final long UPDATE_PROGRESS_INTERVAL_MS = 3 * 1000;

	public AudioShrink(MediaExtractor extractor, MediaMuxer muxer,
			UnrecoverableErrorCallback errorCallback) {
		this.extractor = extractor;
		this.muxer = muxer;
		this.errorCallback = errorCallback;
	}

	public void setBitRate(int bitRate) {
		this.bitRate = bitRate;
	}

	public void setOnProgressListener(OnProgressListener onProgressListener) {
		this.onProgressListener = onProgressListener;
	}

	/**
	 * エンコーダの設定に使うフォーマットを作成する。 <br/>
	 * {@link MediaMuxer#addTrack(MediaFormat)} には利用できない。
	 */
	private MediaFormat createEncoderConfigurationFormat(MediaFormat origin) {
		final int channelCount = origin
				.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
		final MediaFormat format = MediaFormat.createAudioFormat(CODEC,
				origin.getInteger(MediaFormat.KEY_SAMPLE_RATE), channelCount);
		// TODO ビットレートが元の値より大きくならないようにする
		format.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
		format.setInteger(MediaFormat.KEY_AAC_PROFILE, AAC_PROFILE);

		Log.d(LOG_TAG, "create audio encoder configuration format:" + Utils.toString(format));

		return format;
	}

	private void reencode(final int trackIndex, final Integer newTrackIndex,
			final ReencodeListener listener) throws DecodeException {
		final MediaFormat originalFormat = extractor.getTrackFormat(trackIndex);
		Log.d(LOG_TAG, "original format:" + Utils.toString(originalFormat));
		final MediaFormat encoderConfigurationFormat = createEncoderConfigurationFormat(originalFormat);

		MediaCodec encoder = null;
		MediaCodec decoder = null;

		ByteBuffer[] decoderInputBuffers = null;
		ByteBuffer[] decoderOutputBuffers = null;
		MediaCodec.BufferInfo decoderOutputBufferInfo = null;

		ByteBuffer[] encoderInputBuffers = null;
		ByteBuffer[] encoderOutputBuffers = null;
		MediaCodec.BufferInfo encoderOutputBufferInfo = null;

		// 進捗取得に利用
		final float durationUs = originalFormat
				.getLong(MediaFormat.KEY_DURATION);
		final long startTimeNs = System.nanoTime();
		long deliverProgressCount = 0;

		try {
			// create encoder
			encoder = createEncoder(encoderConfigurationFormat);
			encoder.start();

			encoderInputBuffers = encoder.getInputBuffers();
			encoderOutputBuffers = encoder.getOutputBuffers();
			encoderOutputBufferInfo = new MediaCodec.BufferInfo();

			// create decorder
			decoder = createDecoder(originalFormat);
			if (decoder == null) {
				Log.e(LOG_TAG, "audio decoder not found.");
				throw new DecodeException("audio decoder not found.");
{'fraction_non_alphanumeric': 0.08328947368421052, 'fraction_numerical': 0.002763157894736842, 'mean_word_length': 5.307883817427386, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1463761', 'n_tokens_mistral': 2615, 'n_tokens_neox': 2350, 'n_words': 525}