I'm trying to merge a video (mp4) without audio stream with an audio file (mp3). I'm developing under nodewebkit a video software which means that I have to use ogg files, so when the user upload a video or a audio file it converts it in ogg whatever its format. Then when the user want to export its video I’m exporting frames from a canvas to PNG images. Once this is done I’m creating a video from the frames with a 30 fps with this following code:
var videoMaker = function () {
console.log('videoMaker');
var deffered = Q.defer();
if (!FS.existsSync($rootScope.project.path + '/video')) {
filestorageService.createFolder($rootScope.project.path + '/video');
}
audioMaker().then(function () {
var commandVideo = new Ffmpeg({
source: $rootScope.project.path + '/frames/%d.png'
});
commandVideo.setFfmpegPath(ffmpegPath);
commandVideo.addOptions(['-c:v libx264', '-r 30']).withFpsInput(30).format('mp4').on('error', function (err) {
console.log('video', err);
}).on('end', function () {
console.log('video win');
deffered.resolve();
}).save($rootScope.project.path + '/video/rendu.mp4');
});
return deffered.promise;
};
Then i'm reconverting the audio wich has been uploaded by the user to mp3:
var audioMaker = function () {
console.log('audioMaker');
var deffered = Q.defer();
if ($rootScope.project.settings.music.path !== '') {
FS.writeFileSync($rootScope.project.path + '/music/finalMusic.mp3', null);
var commandAudio = new Ffmpeg({
source: $rootScope.project.settings.music.path
});
commandAudio.setFfmpegPath(ffmpegPath);
if ($rootScope.project.settings.music.fadeIn) {
commandAudio.audioFilters('afade=t=in:ss=0:d=0.5');
}
console.log($rootScope.project.settings.music.fadeOut, $rootScope.project.settings.music.fadeIn);
if ($rootScope.project.settings.music.fadeOut) {
var time = sceneService.getTotalDuration() - 0.5;
commandAudio.audioFilters('afade=t=out:st=' + time + ':d=0.5');
}
commandAudio.toFormat('mp3').on('end', function () {
console.log('audio win');
deffered.resolve();
}).on('error', function (err) {
console.log('audio', err);
}).save($rootScope.project.path + '/music/finalMusic.mp3');
} else {
deffered.resolve();
}
return deffered.promise;
};
Until there everything is alright those files work well but when i do this:
var command = new Ffmpeg({
source: $rootScope.project.path + '/video/rendu.mp4'
});
command.setFfmpegPath(ffmpegPath);
console.log($rootScope.project.settings.music.path !== '');
if ($rootScope.project.settings.music.path !== '') {
command.addInput($rootScope.project.path + '/music/finalMusic.mp3');
command.addOptions(['-c:v copy', '-c:a copy']);
if ($rootScope.project.settings.music.duration > sceneService.getTotalDuration()) {
command.addOptions(['-shortest']);
}
command.on('error', function (err) {
console.log(err);
}).on('end', function () {
console.log("win");
//filestorageService.rmFolder($rootScope.project.path + '/frames');
}).save($rootScope.project.path + '/video/rendu.mp4');
} else {
filestorageService.rmFolder($rootScope.project.path + '/frames');
}
And my final file has the music and the right duration but the frames aren't right, any ideas?
I finally find out how to fix this, the final video wasn't good because i was merging the video and the audio to the same video file which means that i was getting the data of the video via outsream while i was writing on the file. So in my program i created a temp folder which contains the video and the audio then i merge them to a new video file which is in an other final folder to finally delete the temp folder.
Related
I am trying to play audio clips of audio receieved from server through socketio. The code works but on the first audio clip recieved is played, any clip recieved afterwards are not played. I confirmed their reciept but I don't know why it only plays the first received audio file.
socketio.on('audio_playback_results', function (data) {
console.log("I recieved an audio playback! ",data);
playOutput(data);
});
function playOutput(arrayBuffer){
let audioContext = new AudioContext();
let outputSource;
try {
if(arrayBuffer.byteLength > 0){
console.log(arrayBuffer.byteLength);
audioContext.decodeAudioData(arrayBuffer,
function(buffer){
audioContext.resume();
outputSource = audioContext.createBufferSource();
outputSource.connect(audioContext.destination);
outputSource.buffer = buffer;
outputSource.start(0);
},
function(){
console.log(`playoutput PLAYING OUTPUT ARGUMMENT ${arguments}`);
// console.log(arguments);
});
}
} catch(e) {
console.log(`ERORRR PLAYING OUTPUT ${e}`);
}
}
i perform a text to audiobuffer on server side and then stream it back to client side.
async function textToAudioBuffer(text) {
requestTTS.input = { text: text }; // text or SSML
const response = await ttsClient.synthesizeSpeech(requestTTS);
console.log("RESPONSE # ttsClient, textToAudioBuffer() : ", response[0].audioContent)
var results = response[0].audioContent
io.emit('audio_playback_results', results);
return response[0].audioContent;
}
what is causing it not to play audio clip recieved after the first one and how can I fix this ?
Trying to play audio files from the external storage of phone.
Went through this plugin first finding the URI for a particular mp3 file. Then passed that to the cordova-plugin-media instance.
// find music file URI from the sdcard
new ExternalStorageSdcardAccess( fileHandler ).scanPath( "file:///storage/C67A-18F7/Music/" );
function fileHandler( fileEntry ) {
// console.log( fileEntry.name + " | " + fileEntry.toURL() );
}
// create a button instance
let mbutton = new Button({
centerX: 0, top: [fbutton,100],
text: 'play music'
}).appendTo(ui.contentView);
// call the play media function from the button
mbutton.on('select', () => {
// load and play the music:
playAudio("file:///storage/C67A-18F7/Music/demo/testSound.mp3")
});
function playAudio(url) {
// Play the audio file at url
var my_media = new Media(url,
// success callback
function () {
console.log("playAudio():Audio Success");
},
// error callback
function (err) {
console.log("playAudio():Audio Error: " + err.code + err.message);
},
// status callback
function (status) {
console.log("playAudio():Audio Status: " + status);
}
);
// Play audio
my_media.play();
my_media.setVolume('1.0');
}
I checked the adb for log. This is what I got specifically hitting those buttons - http://paste.ubuntu.com/25767292/
incoming-operation: 'Call' on 'cordova.plugin' (o13) with method 'exec' with properties {action=create, arguments=["d39113d0-b5f5-bf2d-8a84-5afbbc6ae9a0","file:///storage/C67A-18F7/Music/demo/testSound.mp3"], callbackId=Media975330222}
incoming-operation: 'Call' on 'cordova.plugin' (o13) with method 'exec' with properties {action=startPlayingAudio, arguments=["d39113d0-b5f5-bf2d-8a84-5afbbc6ae9a0","file:///storage/C67A-18F7/Music/demo/testSound.mp3",null], callbackId=INVALID}
outgoing-operation: 'Notify' o13 of 'finish' with arguments {message=S01 Media975330222 s, status=1, keepCallback=false, callbackId=Media975330222}
ExtMediaPlayer-JNI: env->IsInstanceOf fails
MediaPlayer-JNI: JNIMediaPlayerFactory: bIsQCMediaPlayerPresent 0
ExtMediaPlayer-JNI: env->IsInstanceOf fails
MediaPlayer-JNI: JNIMediaPlayerFactory: bIsQCMediaPlayerPresent 0
I am using Capacitor with an ionic react project and was able to get cordova-plugin-media playing local files by using it in conjunction with cordova-plugin-file. I am the ionic-native wrappers, but I think its the same code here.
NOTE: iOS requires you to remove 'file://' and Android does not.
const finishedFilePath = `${File.applicationDirectory}public/assets/audio/file.mp3`;
const hybridTransitionAudioFile = Media.create(isPlatform('ios') ? transitionFilePath.replace('file://', '') : transitionFilePath);
hybridTransitionAudioFile.play();
1- install this
https://play.google.com/store/apps/details?id=com.adobe.phonegap.app&hl=en
2- install this
http://docs.phonegap.com/getting-started/1-install-phonegap/desktop/
3- connect your laptop and your phone on same network
4- follow the getting started on this and run it on your phone , i suppose you wont get the same error , because im my case it dose not work in browser nor emulator in case of phone gap
Reference:
https://phonegap.com/getstarted/
give feed back so i can update my answer here
HTML PART
for audio src
<audio id="successSound" src="/android_asset/www/audio/correct.mp3" type="audio/mpeg"></audio>
<audio id="errorSound" src="/android_asset/www/audio/error.mp3" type="audio/mpeg" ></audio>
</body>
</html>
Example of my version that works i hope there is help in it
playAudio("errorSound");
var my_media = null;
var mediaTimer = null;
function playAudio(id) {
var audioElement = document.getElementById(id);
var src = audioElement.getAttribute('src');
// Create Media object from src
my_media = new Media(src, onSuccess, onError);
// Play audio
my_media.play();
// Update my_media position every second
if (mediaTimer == null) {
mediaTimer = setInterval(function() {
// get my_media position
my_media.getCurrentPosition(
// success callback
function(position) {
if (position > -1) {
setAudioPosition((position) + " sec");
}
},
// error callback
function(e) {
console.log("Error getting pos=" + e);
setAudioPosition("Error: " + e);
}
);
}, 1000);
}
}
function setAudioPosition(position) {
document.getElementById('audio_position').innerHTML = position;
}
// onSuccess Callback
//
function onSuccess() {
}
// onError Callback
function onError(error) {
switch(error.code){
case MediaError.MEDIA_ERR_ABORTED:
alert('MEDIA_ERR_ABORTED code: ' + error.code);
break;
case MediaError.MEDIA_ERR_NETWORK:
alert('MEDIA_ERR_NETWORK code: ' + error.code);
break;
case MediaError.MEDIA_ERR_DECODE:
alert('MEDIA_ERR_DECODE code: ' + error.code);
break;
case MediaError.MEDIA_ERR_NONE_SUPPORTED:
alert('MEDIA_ERR_NONE_SUPPORTED code: ' + error.code);
break;
}
}
I have created an Android app from html5 and JavaScript using ionic/Cordova framework. In there I create and play an audio object as:
var myAudio = new Audio("myfile.mp3") ;
myAudio.play();
If I install the generated apk on Android API 21, audio plays fine. If I install it on API 19 it doesn't play.
Any help on this is really appreciated.
Hi did you install the cordova media plugin?
I did something like that in the past with cordova 4.0.0 (definitely worked on android 19 (4.4.2 to be accurate)):
AckSound:function(){
try{
var pathMedia;
if(device.platform ==='iOS'){
pathMedia ='';
} else {
pathMedia = app.getCordovaPath();
}
var snd =new Media(pathMedia+'mySound.mp3');
// Update media position every second
var mediaTimer = null;
mediaDuration = snd.getDuration();
console.log("mediaDuration is " + mediaDuration);
snd.play();
if(mediaTimer==null){
mediaTimer = setInterval(function () {
// get media position
snd.getCurrentPosition(
// success callback
function (position) {
if (position > 0) {
console.log((position) + " sec");
} else {
//if position isn t > 0, the file is over
snd.stop();
clearInterval(mediaTimer);
mediaTimer = null;
snd.release();
delete snd;
}
},
// error callback
function (e) {
console.log("Error getting pos=" + e);
}
);
}, 100);
};
delete snd;
} catch(err){
console.log("Error: in AudioManagement.AckSound(), Error is " + err);
}
console.log("AudioManagement.AckSound() stops");
}
},
Here is a full example: https://github.com/nyluje/TestMediaPluginCordova
I am trying to return the url of the uploaded image and make it equal to uploadedurl. This is all in a function that is triggered when a photo is dropped into the upload box. uploadedurl is currently being set to null and is returning this error The provided value 'undefined' is not a valid enum value of type XMLHttpRequestResponseType. in the client console. I am using amazon S3 to store the images That part works the images are stored in the S3 and do have usable urls under the domain. What did I do wrong?
var user = Meteor.user();
var uploadedurl;
Images.insert(newFile, function (error, fileObj) {
if (error) {
//do error
} else {
fileObj.once("uploaded", function () {
uploadedurl=fileObj.url();
document.getElementById("phototag").innerHTML = '<img src="'+uploadedurl+'" >';
});
}
});
});
},
CollectionFS objects include a url() method. In your case use:
fileObj.url();
Note that it may take awhile for large files to finish uploading. fileObj.isUploaded() will be true when the upload is done. fileObj.url() will be null until that time.
In this github ticket #aldeed mentions attaching an event handler to the fileObj to be able to get a callback once the file uploads. This is better than polling with a setTimeout. In your case:
fileObj.once("uploaded", function () {
uploadedurl=fileObj.url();
});
try this..It worked for me
FS.Utility.eachFile(event, function(file) {
Images.insert(file, function(err, fileObj) {
if (err) {
console.log(err);
} else {
var cursor = Images.find(fileObj._id);
var liveQuery = cursor.observe({
changed: function(newImage, oldImage) {
if (newImage.isUploaded()) {
liveQuery.stop();
$("#image" + postId).attr("fileId", fileObj._id);
var fielname = fileObj.original.name;
setTimeout(function() {
var imageUrl = '/cfs/files/images/' + fileObj._id + '/' + fielname;
$("#imagefile" + postId).attr("src", imageUrl);
$("#imagediv" + postId).show();
}, 5000);
}
}
});
}
});});
I'm trying to write an Android app with PhoneGap that contains multiple HTML files. In every HTML I would like to include an mp3 file that the user can play and stop. This has worked so far. The problem that I encounter is when trying to put multiple mp3 files in one file.
The thing that I would like to achieve is to put the general audio player javescript in one file and to tell in the HTML which file should be played. Is this possible and how? Thanks!
My code for one of the html files looks like this:
<script type="text/javascript" charset="utf-8" src="phonegap.js"></script>
<script type="text/javascript" charset="utf-8">
//-------------------------------------------------------------------------
// Audio player
//-------------------------------------------------------------------------
var media1 = null;
var media1Timer = null;
var audioSrc = null;
/**
* Play audio
*/
function playAudio(url) {
console.log("playAudio()");
console.log(" -- media="+media1);
//var src = "/android_asset/www/audio/01.mp3";
var src = "/android_asset/www/audio/01.mp3";
if (url) {
src = url;
}
// Stop playing if src is different from currently playing source
if (src != audioSrc) {
if (media1 != null) {
stopAudio();
media1 = null;
}
}
if (media1 == null) {
media1 = new Media(src,
function() {
console.log("playAudio():Audio Success");
},
function(err) {
console.log("playAudio():Audio Error: "+err);
setAudioStatus("Error: " + err);
},
function(status) {
console.log("playAudio():Audio Status: "+status);
setAudioStatus(Media.MEDIA_MSG[status]);
// If stopped, then stop getting current position
if (Media.MEDIA_STOPPED == status) {
clearInterval(media1Timer);
media1Timer = null;
}
});
}
audioSrc = src;
// Play audio
media1.play();
if (media1Timer == null) {
media1Timer = setInterval(
function() {
media1.getCurrentPosition(
function(position) {
console.log("Pos="+position);
if (position > -1) {
setAudioPosition((position/1000)+" sec");
}
},
function(e) {
console.log("Error getting pos="+e);
setAudioPosition("Error: "+e);
}
);
},
1000
);
}
// Get duration
var counter = 0;
var timerDur = setInterval(
function() {
counter = counter + 100;
if (counter > 2000) {
clearInterval(timerDur);
}
var dur = media1.getDuration();
if (dur > 0) {
clearInterval(timerDur);
document.getElementById('audio_duration').innerHTML = (dur/1000) + " sec";
}
}, 100);
}
/**
* Pause audio playback
*/
function pauseAudio() {
console.log("pauseAudio()");
if (media1) {
media1.pause();
}
}
/**
* Stop audio
*/
function stopAudio() {
console.log("stopAudio()");
if (media1) {
media1.stop();
}
clearInterval(media1Timer);
media1Timer = null;
}
/**
* Set audio status
*/
var setAudioStatus = function(status) {
document.getElementById('audio_status').innerHTML = status;
};
/**
* Set audio position
*/
var setAudioPosition = function(position) {
document.getElementById('audio_position').innerHTML = position;
};
</script>
</head>
<body>
<!-- Audio -->
<div id="info">
<h2>Audio</h2>
</div>
Play
Pause
Stop
</body>
You might consider using a page with a frame on it. Place your common javascript in the of the main page and then call back to parent.playAudio(src) to kick off the player from each sub-page as it's loaded into the frame.
Another possible direction is use of jqMobile. By default, jqMobile loads pages using Ajax calls..consequently, your javascript can be loaded by the very first page only...and all subsequent page loads via ajax do not totally replace the DOM...leaving your javascript in tact. I have developed a small app using phonegap and jqMobile with fairly good success.