use of protect.videotranscoder.media.MediaContainer in project video-transcoder by brarcher.
the class MainActivity method populateOptionDefaults.
private void populateOptionDefaults() {
for (int id : BASIC_SETTINGS_IDS) {
findViewById(id).setVisibility(View.VISIBLE);
}
for (int id : VIDEO_SETTINGS_IDS) {
findViewById(id).setVisibility(View.VISIBLE);
}
for (int id : AUDIO_SETTINGS_IDS) {
findViewById(id).setVisibility(View.VISIBLE);
}
encodeButton.setVisibility(View.VISIBLE);
startJumpBack.setVisibility(View.VISIBLE);
startJumpForward.setVisibility(View.VISIBLE);
endJumpBack.setVisibility(View.VISIBLE);
endJumpForward.setVisibility(View.VISIBLE);
final String customString = getString(R.string.custom);
containerSpinner.setAdapter(new ArrayAdapter<>(this, R.layout.spinner_textview, MediaContainer.values()));
containerSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
MediaContainer container = (MediaContainer) parentView.getItemAtPosition(position);
int visibility = container.supportedVideoCodecs.size() > 0 ? View.VISIBLE : View.GONE;
for (int resId : VIDEO_SETTINGS_IDS) {
findViewById(resId).setVisibility(visibility);
}
if (resolutionSpinner.getSelectedItem().toString().equals(customString) == false) {
findViewById(R.id.resolutionCustomContainer).setVisibility(View.GONE);
}
visibility = container.supportedAudioCodecs.size() > 0 ? View.VISIBLE : View.GONE;
for (int resId : AUDIO_SETTINGS_IDS) {
findViewById(resId).setVisibility(visibility);
}
// Hide video bitrate for GIF, as it does not apply
if (container == MediaContainer.GIF) {
findViewById(R.id.videoBitrateContainer).setVisibility(View.GONE);
}
VideoCodecWrapper currentVideoSelection = (VideoCodecWrapper) videoCodecSpinner.getSelectedItem();
AudioCodec currentAudioSelection = (AudioCodec) audioCodecSpinner.getSelectedItem();
videoCodecSpinner.setAdapter(new ArrayAdapter<>(MainActivity.this, R.layout.spinner_textview, VideoCodecWrapper.wrap(MainActivity.this, container.supportedVideoCodecs)));
audioCodecSpinner.setAdapter(new ArrayAdapter<>(MainActivity.this, R.layout.spinner_textview, container.supportedAudioCodecs));
// Attempt to set the same settings again, if they exist
if (currentVideoSelection != null) {
setSpinnerSelection(videoCodecSpinner, currentVideoSelection.codec);
}
if (currentAudioSelection != null) {
setSpinnerSelection(audioCodecSpinner, currentAudioSelection.toString());
}
}
@Override
public void onNothingSelected(AdapterView<?> parentView) {
// Nothing to do
}
});
class SetCustomAdapter implements AdapterView.OnItemSelectedListener {
private final String customString;
private final View customField;
public SetCustomAdapter(String customString, @IdRes int customFieldId) {
this.customString = customString;
this.customField = findViewById(customFieldId);
}
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
String value = (String) parent.getItemAtPosition(position);
MediaContainer container = (MediaContainer) containerSpinner.getSelectedItem();
if (value.equals(customString) && container.supportedVideoCodecs.size() > 0) {
customField.setVisibility(View.VISIBLE);
} else {
customField.setVisibility(View.GONE);
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
// Nothing to do
}
}
LinkedList<String> fps = new LinkedList<>(Arrays.asList("15", "24", "23.98", "25", "29.97", "30", "50"));
if (videoInfo.videoFramerate != null && fps.contains(videoInfo.videoFramerate) == false) {
fps.add(videoInfo.videoFramerate);
Collections.sort(fps);
}
fpsSpinner.setAdapter(new ArrayAdapter<>(this, R.layout.spinner_textview, fps));
LinkedList<String> resolution = new LinkedList<>();
if (videoInfo.videoResolution != null && resolution.contains(videoInfo.videoResolution) == false) {
resolution.add(videoInfo.videoResolution);
int width = Integer.parseInt(videoInfo.videoResolution.split("x")[0]);
int height = Integer.parseInt(videoInfo.videoResolution.split("x")[1]);
// Add a few derivatives of this resolution as well
resolution.add((width / 2) + "x" + (height / 2));
resolution.add((width / 4) + "x" + (height / 4));
Collections.sort(resolution, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
int width1 = Integer.parseInt(o1.split("x")[0]);
int height1 = Integer.parseInt(o1.split("x")[1]);
int width2 = Integer.parseInt(o2.split("x")[0]);
int height2 = Integer.parseInt(o2.split("x")[1]);
if (width1 != width2) {
return width1 - width2;
} else {
return height1 - height2;
}
}
});
}
resolution.addLast(customString);
resolutionSpinner.setAdapter(new ArrayAdapter<>(this, R.layout.spinner_textview, resolution));
resolutionSpinner.setOnItemSelectedListener(new SetCustomAdapter(customString, R.id.resolutionCustomContainer));
audioCodecSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
AudioCodec audioCodec = (AudioCodec) parentView.getItemAtPosition(position);
String currentSelection = (String) audioChannelSpinner.getSelectedItem();
audioChannelSpinner.setAdapter(new ArrayAdapter<>(MainActivity.this, R.layout.spinner_textview, audioCodec.supportedChannels));
// Attempt to set the same setting as before, if it exists
if (currentSelection != null) {
setSpinnerSelection(audioChannelSpinner, currentSelection);
}
}
@Override
public void onNothingSelected(AdapterView<?> parentView) {
// Nothing to do
}
});
List<Integer> audioBitrateK = new ArrayList<>(Arrays.asList(15, 24, 32, 64, 96, 128, 192, 256, 320, 384, 448, 512));
if (videoInfo.audioBitrateK != null && audioBitrateK.contains(videoInfo.audioBitrateK) == false) {
audioBitrateK.add(videoInfo.audioBitrateK);
Collections.sort(audioBitrateK);
}
audioBitrateSpinner.setAdapter(new ArrayAdapter<>(this, R.layout.spinner_textview, audioBitrateK));
List<Integer> sampleRate = new ArrayList<>(Arrays.asList(8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000));
if (videoInfo.audioSampleRate != null && audioBitrateK.contains(videoInfo.audioSampleRate) == false) {
sampleRate.add(videoInfo.audioSampleRate);
Collections.sort(sampleRate);
}
audioSampleRateSpinner.setAdapter(new ArrayAdapter<>(this, R.layout.spinner_textview, sampleRate));
String[] channels = new String[] { "1", "2" };
audioChannelSpinner.setAdapter(new ArrayAdapter<>(this, R.layout.spinner_textview, channels));
if (videoInfo.container != null) {
setSpinnerSelection(containerSpinner, videoInfo.container.toString());
}
if (videoInfo.videoCodec != null) {
setSpinnerSelection(videoCodecSpinner, videoInfo.videoCodec);
}
if (videoInfo.videoFramerate != null) {
setSpinnerSelection(fpsSpinner, videoInfo.videoFramerate);
}
if (videoInfo.videoResolution != null) {
setSpinnerSelection(resolutionSpinner, videoInfo.videoResolution);
}
if (videoInfo.videoBitrateK != null) {
videoBitrateValue.setText(Integer.toString(videoInfo.videoBitrateK));
}
if (videoInfo.audioCodec != null) {
setSpinnerSelection(audioCodecSpinner, videoInfo.audioCodec.toString());
}
Integer defaultAudioBitrateK = videoInfo.audioBitrateK;
if (defaultAudioBitrateK == null) {
// Set some default if none is detected
defaultAudioBitrateK = 128;
}
setSpinnerSelection(audioBitrateSpinner, defaultAudioBitrateK);
if (videoInfo.audioSampleRate != null) {
setSpinnerSelection(audioSampleRateSpinner, videoInfo.audioSampleRate);
}
setSpinnerSelection(audioChannelSpinner, Integer.toString(videoInfo.audioChannels));
}
use of protect.videotranscoder.media.MediaContainer in project video-transcoder by brarcher.
the class MainActivity method startEncode.
private void startEncode() {
MediaContainer container = (MediaContainer) containerSpinner.getSelectedItem();
VideoCodecWrapper videoCodecWrapper = (VideoCodecWrapper) videoCodecSpinner.getSelectedItem();
VideoCodec videoCodec = videoCodecWrapper != null ? videoCodecWrapper.codec : null;
String fps = (String) fpsSpinner.getSelectedItem();
String resolution = (String) resolutionSpinner.getSelectedItem();
AudioCodec audioCodec = (AudioCodec) audioCodecSpinner.getSelectedItem();
Integer audioBitrateK = (Integer) audioBitrateSpinner.getSelectedItem();
Integer audioSampleRate = (Integer) audioSampleRateSpinner.getSelectedItem();
String audioChannel = (String) audioChannelSpinner.getSelectedItem();
int videoBitrateK = 0;
if (videoInfo == null) {
Toast.makeText(this, R.string.selectFileFirst, Toast.LENGTH_LONG).show();
return;
}
final String customString = getString(R.string.custom);
if (resolution.equals(customString) && container.supportedVideoCodecs.size() > 0) {
resolution = resolutionCustom.getText().toString();
String[] split = resolution.split("x");
if (split.length != 2) {
Toast.makeText(this, R.string.videoResolutionValueInvalid, Toast.LENGTH_LONG).show();
return;
}
for (String value : split) {
try {
// Check if the string can be parsed or not.
Integer.parseInt(value);
} catch (NumberFormatException e) {
Toast.makeText(this, R.string.videoResolutionValueInvalid, Toast.LENGTH_LONG).show();
return;
}
}
}
try {
// Ignore video bitrate for GIF
if (container != MediaContainer.GIF) {
String videoBitrateKStr = videoBitrateValue.getText().toString();
videoBitrateK = Integer.parseInt(videoBitrateKStr);
}
} catch (NumberFormatException e) {
Toast.makeText(this, R.string.videoBitrateValueInvalid, Toast.LENGTH_LONG).show();
return;
}
File outputDir;
if (container.supportedVideoCodecs.size() > 0) {
outputDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES);
} else {
outputDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC);
}
if (outputDir.exists() == false) {
boolean result = outputDir.mkdirs();
if (result == false) {
Log.w(TAG, "Unable to create destination dir: " + outputDir.getAbsolutePath());
}
}
String fileBaseName = videoInfo.getFileBaseName();
String extension = "." + container.extension;
String inputFilePath = videoInfo.file.getAbsolutePath();
File destination = new File(outputDir, fileBaseName + extension);
int fileNo = 0;
while (destination.exists()) {
fileNo++;
destination = new File(outputDir, fileBaseName + "_" + fileNo + extension);
}
int startTimeSec = rangeSeekBar.getSelectedMinValue().intValue();
int endTimeSec = rangeSeekBar.getSelectedMaxValue().intValue();
int durationSec = (int) (videoInfo.durationMs / 1000);
startEncode(inputFilePath, startTimeSec, endTimeSec, durationSec, container, videoCodec, videoBitrateK, resolution, fps, audioCodec, audioSampleRate, audioChannel, audioBitrateK, destination.getAbsolutePath());
}
use of protect.videotranscoder.media.MediaContainer in project video-transcoder by brarcher.
the class FFmpegUtil method parseMediaInfo.
static MediaInfo parseMediaInfo(File mediaFile, String mediaDetailsJsonStr) {
long durationMs = 0;
Integer totalBitrateK = null;
MediaContainer container = null;
VideoCodec videoCodec = null;
String videoResolution = null;
Integer videoBitrateK = null;
String videoFramerate = null;
AudioCodec audioCodec = null;
Integer audioSampleRate = null;
Integer audioBitrateK = null;
int audioChannels = 2;
/*
* Example output:
{
"streams": [
{
"index": 0,
"codec_name": "h264",
"codec_long_name": "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10",
"profile": "Main",
"codec_type": "video",
"codec_time_base": "1/50",
"codec_tag_string": "[0][0][0][0]",
"codec_tag": "0x0000",
"width": 640,
"height": 360,
"coded_width": 640,
"coded_height": 360,
"has_b_frames": 0,
"sample_aspect_ratio": "1:1",
"display_aspect_ratio": "16:9",
"pix_fmt": "yuv420p",
"level": 30,
"chroma_location": "left",
"refs": 1,
"is_avc": "true",
"nal_length_size": "4",
"r_frame_rate": "25/1",
"avg_frame_rate": "25/1",
"time_base": "1/1000",
"start_pts": 0,
"start_time": "0.000000",
"bits_per_raw_sample": "8",
"disposition": {
"default": 0,
"dub": 0,
"original": 0,
"comment": 0,
"lyrics": 0,
"karaoke": 0,
"forced": 0,
"hearing_impaired": 0,
"visual_impaired": 0,
"clean_effects": 0,
"attached_pic": 0
}
},
{
"index": 1,
"codec_name": "aac",
"codec_long_name": "AAC (Advanced Audio Coding)",
"profile": "LC",
"codec_type": "audio",
"codec_time_base": "1/44100",
"codec_tag_string": "[0][0][0][0]",
"codec_tag": "0x0000",
"sample_fmt": "fltp",
"sample_rate": "48000",
"channels": 6,
"channel_layout": "5.1",
"bits_per_sample": 0,
"r_frame_rate": "0/0",
"avg_frame_rate": "0/0",
"time_base": "1/1000",
"start_pts": 3,
"start_time": "0.003000",
"disposition": {
"default": 0,
"dub": 0,
"original": 0,
"comment": 0,
"lyrics": 0,
"karaoke": 0,
"forced": 0,
"hearing_impaired": 0,
"visual_impaired": 0,
"clean_effects": 0,
"attached_pic": 0
}
}
],
"format": {
"filename": "/Users/brarcher/Downloads/big_buck_bunny_360p_1mb.flv",
"nb_streams": 2,
"nb_programs": 0,
"format_name": "flv",
"format_long_name": "FLV (Flash Video)",
"start_time": "0.000000",
"duration": "6.893000",
"size": "1048720",
"bit_rate": "1217142",
"probe_score": 100,
"tags": {
"encoder": "Lavf53.24.2"
}
}
}
*/
ObjectMapper mapper = new ObjectMapper();
try {
JsonNode root = mapper.readTree(mediaDetailsJsonStr);
if (root != null) {
JsonNode format = root.get("format");
if (format != null) {
JsonNode duration = format.get("duration");
if (duration != null) {
durationMs = (int) (duration.asDouble() * 1000);
}
JsonNode bitrate = format.get("bit_rate");
if (bitrate != null) {
totalBitrateK = bitrate.asInt() / 1000;
}
JsonNode formatName = format.get("format_name");
if (formatName != null) {
String formatNameStr = formatName.asText();
for (MediaContainer item : MediaContainer.values()) {
if (formatNameStr.contains(item.ffmpegName)) {
container = item;
break;
}
}
}
}
JsonNode streams = root.get("streams");
if (streams != null) {
for (int index = 0; index < streams.size(); index++) {
JsonNode stream = streams.get(index);
JsonNode codecType = stream.get("codec_type");
if (codecType == null) {
continue;
}
if (codecType.asText().equals("video")) {
JsonNode codecName = stream.get("codec_name");
if (codecName == null) {
continue;
}
videoCodec = VideoCodec.fromName(codecName.asText());
JsonNode width = stream.get("width");
JsonNode height = stream.get("height");
if (width == null || height == null) {
continue;
}
videoResolution = width + "x" + height;
// bit_rate may not always be available, so do not require it.
JsonNode bitrate = stream.get("bit_rate");
if (bitrate != null) {
videoBitrateK = bitrate.asInt() / 1000;
}
JsonNode frameRate = stream.get("avg_frame_rate");
if (frameRate == null) {
continue;
}
try {
String frameRateStr = frameRate.asText();
String[] frameRateSplit = frameRateStr.split("/");
int frameRateNum = Integer.parseInt(frameRateSplit[0]);
int frameRateDem = 1;
if (frameRateSplit.length > 1) {
frameRateDem = Integer.parseInt(frameRateSplit[1]);
}
double frameRateValue = frameRateNum / (double) frameRateDem;
videoFramerate = String.format(Locale.US, "%.2f", frameRateValue);
if (videoFramerate.contains(".00")) {
videoFramerate = videoFramerate.replace(".00", "");
}
} catch (NumberFormatException e) {
continue;
}
}
if (codecType.asText().equals("audio")) {
JsonNode codecName = stream.get("codec_name");
if (codecName == null) {
continue;
}
audioCodec = AudioCodec.fromName(codecName.asText());
JsonNode sampleRate = stream.get("sample_rate");
if (sampleRate == null) {
continue;
}
audioSampleRate = sampleRate.asInt();
// bit_rate may not always be available, so do not require it.
JsonNode bitrate = stream.get("bit_rate");
if (bitrate != null) {
audioBitrateK = bitrate.asInt() / 1000;
}
JsonNode channelLaoyout = stream.get("channel_layout");
if (channelLaoyout == null) {
continue;
}
audioChannels = channelLaoyout.asText().equals("mono") ? 1 : 2;
}
}
}
}
} catch (IOException e) {
Log.w(TAG, "Failed to read media details for file : " + mediaFile.getAbsolutePath() + "\n" + mediaDetailsJsonStr, e);
}
if (totalBitrateK != null) {
if (videoBitrateK == null) {
if (audioBitrateK != null) {
// We know the audio bitrate, we can calculate the video bitrate
videoBitrateK = totalBitrateK - audioBitrateK;
}
if (videoBitrateK == null) {
// We do not know any of the separate bitrates. Lets guess 100 kb/s for the audio,
// and subtract that from the total to guess the video bitrate.
// As a guess, subtract 100 kb/s from the bitrate for audio, and
// assume that the video is the rest. This should be a decent-ish
// estimate if the video bitrate cannot be found later.
videoBitrateK = totalBitrateK - 100;
}
}
}
MediaInfo info = null;
if (container != null && (videoCodec != null || audioCodec != null)) {
info = new MediaInfo(mediaFile, durationMs, container, videoCodec, videoResolution, videoBitrateK, videoFramerate, audioCodec, audioSampleRate, audioBitrateK, audioChannels);
}
return info;
}
use of protect.videotranscoder.media.MediaContainer in project video-transcoder by brarcher.
the class MainActivity method handleEncodeIntent.
private void handleEncodeIntent(Intent intent) {
final String inputFilePath = intent.getStringExtra("inputVideoFilePath");
final String destinationFilePath = intent.getStringExtra("outputFilePath");
String mediaContainerStr = intent.getStringExtra("mediaContainer");
final MediaContainer container = MediaContainer.fromName(mediaContainerStr);
String videoCodecStr = intent.getStringExtra("videoCodec");
final VideoCodec videoCodec = VideoCodec.fromName(videoCodecStr);
int tmpCideoBitrateK = intent.getIntExtra("videoBitrateK", -1);
final Integer videoBitrateK = tmpCideoBitrateK != -1 ? tmpCideoBitrateK : null;
final String resolution = intent.getStringExtra("resolution");
final String fps = intent.getStringExtra("fps");
String audioCodecStr = intent.getStringExtra("audioCodec");
final AudioCodec audioCodec = AudioCodec.fromName(audioCodecStr);
int tmpAudioSampleRate = intent.getIntExtra("audioSampleRate", -1);
final Integer audioSampleRate = tmpAudioSampleRate != -1 ? tmpAudioSampleRate : null;
final String audioChannel = intent.getStringExtra("audioChannel");
int tmpAudioBitrateK = intent.getIntExtra("audioBitrateK", -1);
final Integer audioBitrateK = tmpAudioBitrateK != -1 ? tmpAudioBitrateK : null;
boolean skipDialog = intent.getBooleanExtra("skipDialog", false);
List<Triplet<Object, Integer, String>> nullChecks = new LinkedList<>();
nullChecks.add(new Triplet<>(inputFilePath, R.string.fieldMissingError, "inputFilePath"));
nullChecks.add(new Triplet<>(destinationFilePath, R.string.fieldMissingError, "outputFilePath"));
nullChecks.add(new Triplet<>(container, R.string.fieldMissingOrInvalidError, "mediaContainer"));
if (container != null && container.supportedVideoCodecs.size() > 0) {
nullChecks.add(new Triplet<>(videoCodec, R.string.fieldMissingOrInvalidError, "videoCodec"));
nullChecks.add(new Triplet<>(videoBitrateK, R.string.fieldMissingError, "videoBitrateK missing"));
nullChecks.add(new Triplet<>(resolution, R.string.fieldMissingError, "resolution"));
nullChecks.add(new Triplet<>(fps, R.string.fieldMissingError, "fps"));
}
if (container != null && container.supportedAudioCodecs.size() > 0) {
nullChecks.add(new Triplet<>(audioCodec, R.string.fieldMissingOrInvalidError, "audioCodec"));
nullChecks.add(new Triplet<>(audioSampleRate, R.string.fieldMissingError, "audioSampleRate"));
nullChecks.add(new Triplet<>(audioChannel, R.string.fieldMissingError, "audioChannel"));
nullChecks.add(new Triplet<>(audioBitrateK, R.string.fieldMissingError, "audioBitrateK"));
}
for (Triplet<Object, Integer, String> check : nullChecks) {
if (check.getValue0() == null) {
String submsg = String.format(getString(check.getValue1()), check.getValue2());
String message = String.format(getString(R.string.cannotEncodeFile), submsg);
Log.i(TAG, message);
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
finish();
return;
}
}
String message = String.format(getString(R.string.encodeStartConfirmation), inputFilePath, destinationFilePath);
DialogInterface.OnClickListener positiveButtonListener = new DialogInterface.OnClickListener() {
public void onClick(final DialogInterface dialog, int which) {
FFmpegUtil.getMediaDetails(new File(inputFilePath), new ResultCallbackHandler<MediaInfo>() {
@Override
public void onResult(MediaInfo result) {
if (result != null) {
int durationSec = (int) (result.durationMs / 1000);
startEncode(inputFilePath, 0, durationSec, durationSec, container, videoCodec, videoBitrateK, resolution, fps, audioCodec, audioSampleRate, audioChannel, audioBitrateK, destinationFilePath);
} else {
String message = String.format(getString(R.string.transcodeFailed), getString(R.string.couldNotFindFileSubmsg));
Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG).show();
finish();
dialog.dismiss();
}
}
});
}
};
AlertDialog dialog = new AlertDialog.Builder(this).setMessage(message).setCancelable(false).setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
dialog.dismiss();
}
}).setPositiveButton(R.string.encode, positiveButtonListener).create();
dialog.show();
if (skipDialog) {
positiveButtonListener.onClick(dialog, 0);
dialog.dismiss();
}
}
Aggregations