Recherche avancée

Médias (0)

Mot : - Tags -/clipboard

Aucun média correspondant à vos critères n’est disponible sur le site.

Autres articles (29)

  • Gestion générale des documents

    13 mai 2011, par

    MédiaSPIP ne modifie jamais le document original mis en ligne.
    Pour chaque document mis en ligne il effectue deux opérations successives : la création d’une version supplémentaire qui peut être facilement consultée en ligne tout en laissant l’original téléchargeable dans le cas où le document original ne peut être lu dans un navigateur Internet ; la récupération des métadonnées du document original pour illustrer textuellement le fichier ;
    Les tableaux ci-dessous expliquent ce que peut faire MédiaSPIP (...)

  • La file d’attente de SPIPmotion

    28 novembre 2010, par

    Une file d’attente stockée dans la base de donnée
    Lors de son installation, SPIPmotion crée une nouvelle table dans la base de donnée intitulée spip_spipmotion_attentes.
    Cette nouvelle table est constituée des champs suivants : id_spipmotion_attente, l’identifiant numérique unique de la tâche à traiter ; id_document, l’identifiant numérique du document original à encoder ; id_objet l’identifiant unique de l’objet auquel le document encodé devra être attaché automatiquement ; objet, le type d’objet auquel (...)

  • Pas question de marché, de cloud etc...

    10 avril 2011

    Le vocabulaire utilisé sur ce site essaie d’éviter toute référence à la mode qui fleurit allègrement
    sur le web 2.0 et dans les entreprises qui en vivent.
    Vous êtes donc invité à bannir l’utilisation des termes "Brand", "Cloud", "Marché" etc...
    Notre motivation est avant tout de créer un outil simple, accessible à pour tout le monde, favorisant
    le partage de créations sur Internet et permettant aux auteurs de garder une autonomie optimale.
    Aucun "contrat Gold ou Premium" n’est donc prévu, aucun (...)

Sur d’autres sites (5141)

  • Merged Video Contains Inverted Clips After First Video Ends

    3 février, par Nikunj Agrawal

    I am working on a Flutter application that merges multiple videos using ffmpeg_kit_flutter . However, after merging, I notice that the second video (and any subsequent ones) appear inverted or rotated in the final output.

    


    Issue Details :

    


      

    1. The first video appears normal.
    2. 


    3. The videos can be recorded using both front and back cameras.
    4. 


    5. The second (and later) videos are flipped or rotated upside down.
    6. 


    7. This happens after merging using ffmpeg_kit_flutter.
    8. 


    


    Question :
How can I correctly merge multiple videos in Flutter without rotation issues ? Is there a way to normalize video orientation before merging using ffmpeg_kit_flutter ?

    


    Any help would be appreciated ! 🚀

    


    Code :

    


    import &#x27;dart:io&#x27;;&#xA;import &#x27;dart:math&#x27;;&#xA;&#xA;import &#x27;package:camera/camera.dart&#x27;;&#xA;import &#x27;package:ffmpeg_kit_flutter/ffmpeg_kit.dart&#x27;;&#xA;import &#x27;package:ffmpeg_kit_flutter/return_code.dart&#x27;;&#xA;import &#x27;package:flutter/material.dart&#x27;;&#xA;import &#x27;package:path_provider/path_provider.dart&#x27;;&#xA;import &#x27;package:permission_handler/permission_handler.dart&#x27;;&#xA;import &#x27;package:record/record.dart&#x27;;&#xA;import &#x27;package:videotest/video_player.dart&#x27;;&#xA;&#xA;class MergeVideoRecording extends StatefulWidget {&#xA;  const MergeVideoRecording({super.key});&#xA;&#xA;  @override&#xA;  State<mergevideorecording> createState() => _MergeVideoRecordingState();&#xA;}&#xA;&#xA;class _MergeVideoRecordingState extends State<mergevideorecording> {&#xA;  CameraController? _cameraController;&#xA;  final AudioRecorder _audioRecorder = AudioRecorder();&#xA;&#xA;  bool _isRecording = false;&#xA;  String? _videoPath;&#xA;  String? _audioPath;&#xA;  List<cameradescription> _cameras = [];&#xA;  int _currentCameraIndex = 0;&#xA;  final List<string> _recordedVideos = [];&#xA;&#xA;  @override&#xA;  Widget build(BuildContext context) {&#xA;    return Scaffold(&#xA;      body: Column(&#xA;        mainAxisAlignment: MainAxisAlignment.center,&#xA;        children: [&#xA;          _cameraController != null &amp;&amp; _cameraController!.value.isInitialized&#xA;              ? SizedBox(&#xA;                  width: MediaQuery.of(context).size.width * 0.4,&#xA;                  height: MediaQuery.of(context).size.height * 0.3,&#xA;                  child: Stack(&#xA;                    children: [&#xA;                      ClipRRect(&#xA;                        borderRadius: BorderRadius.circular(16),&#xA;                        child: SizedBox(&#xA;                          width: MediaQuery.of(context).size.width * 0.4,&#xA;                          height: MediaQuery.of(context).size.height * 0.3,&#xA;                          child: Transform(&#xA;                            alignment: Alignment.center,&#xA;                            transform:&#xA;                                _cameras[_currentCameraIndex].lensDirection ==&#xA;                                        CameraLensDirection.front&#xA;                                    ? Matrix4.rotationY(pi)&#xA;                                    : Matrix4.identity(),&#xA;                            child: CameraPreview(_cameraController!),&#xA;                          ),&#xA;                        ),&#xA;                      ),&#xA;                      Align(&#xA;                        alignment: Alignment.topRight,&#xA;                        child: InkWell(&#xA;                          onTap: _switchCamera,&#xA;                          child: const Padding(&#xA;                            padding: EdgeInsets.all(8.0),&#xA;                            child: CircleAvatar(&#xA;                              radius: 18,&#xA;                              backgroundColor: Colors.white,&#xA;                              child: Icon(&#xA;                                Icons.flip_camera_android,&#xA;                                color: Colors.black,&#xA;                              ),&#xA;                            ),&#xA;                          ),&#xA;                        ),&#xA;                      ),&#xA;                    ],&#xA;                  ),&#xA;                )&#xA;              : const CircularProgressIndicator(),&#xA;          const SizedBox(height: 16),&#xA;          Row(&#xA;            mainAxisAlignment: MainAxisAlignment.center,&#xA;            children: [&#xA;              FloatingActionButton(&#xA;                heroTag: &#x27;record_button&#x27;,&#xA;                onPressed: _toggleRecording,&#xA;                child: Icon(&#xA;                  _isRecording ? Icons.stop : Icons.video_camera_back,&#xA;                ),&#xA;              ),&#xA;              const SizedBox(&#xA;                width: 50,&#xA;              ),&#xA;              FloatingActionButton(&#xA;                heroTag: &#x27;merge_button&#x27;,&#xA;                onPressed: _mergeVideos,&#xA;                child: const Icon(&#xA;                  Icons.merge,&#xA;                ),&#xA;              ),&#xA;            ],&#xA;          ),&#xA;          if (!_isRecording)&#xA;            ListView.builder(&#xA;              shrinkWrap: true,&#xA;              itemCount: _recordedVideos.length,&#xA;              itemBuilder: (context, index) => InkWell(&#xA;                onTap: () {&#xA;                  Navigator.push(&#xA;                    context,&#xA;                    MaterialPageRoute(&#xA;                      builder: (context) => VideoPlayerScreen(&#xA;                        videoPath: _recordedVideos[index],&#xA;                      ),&#xA;                    ),&#xA;                  );&#xA;                },&#xA;                child: ListTile(&#xA;                  title: Text(&#x27;Video ${index &#x2B; 1}&#x27;),&#xA;                  subtitle: Text(&#x27;Path ${_recordedVideos[index]}&#x27;),&#xA;                  trailing: const Icon(Icons.play_arrow),&#xA;                ),&#xA;              ),&#xA;            ),&#xA;        ],&#xA;      ),&#xA;    );&#xA;  }&#xA;&#xA;  @override&#xA;  void dispose() {&#xA;    _cameraController?.dispose();&#xA;    _audioRecorder.dispose();&#xA;    super.dispose();&#xA;  }&#xA;&#xA;  @override&#xA;  void initState() {&#xA;    super.initState();&#xA;    _initializeDevices();&#xA;  }&#xA;&#xA;  Future<void> _initializeCameraController(CameraDescription camera) async {&#xA;    _cameraController = CameraController(&#xA;      camera,&#xA;      ResolutionPreset.high,&#xA;      enableAudio: true,&#xA;      imageFormatGroup: ImageFormatGroup.yuv420, // Add this line&#xA;    );&#xA;&#xA;    await _cameraController!.initialize();&#xA;    await _cameraController!.setExposureMode(ExposureMode.auto);&#xA;    await _cameraController!.setFocusMode(FocusMode.auto);&#xA;    setState(() {});&#xA;  }&#xA;&#xA;  Future<void> _initializeDevices() async {&#xA;    final cameraStatus = await Permission.camera.request();&#xA;    final micStatus = await Permission.microphone.request();&#xA;&#xA;    if (!cameraStatus.isGranted || !micStatus.isGranted) {&#xA;      _showError(&#x27;Camera and microphone permissions required&#x27;);&#xA;      return;&#xA;    }&#xA;&#xA;    _cameras = await availableCameras();&#xA;    if (_cameras.isNotEmpty) {&#xA;      final frontCameraIndex = _cameras.indexWhere(&#xA;          (camera) => camera.lensDirection == CameraLensDirection.front);&#xA;      _currentCameraIndex = frontCameraIndex != -1 ? frontCameraIndex : 0;&#xA;      await _initializeCameraController(_cameras[_currentCameraIndex]);&#xA;    }&#xA;  }&#xA;&#xA;  // Merge video&#xA;  Future<void> _mergeVideos() async {&#xA;    if (_recordedVideos.isEmpty) {&#xA;      _showError(&#x27;No videos to merge&#x27;);&#xA;      return;&#xA;    }&#xA;&#xA;    try {&#xA;      // Debug logging&#xA;      print(&#x27;Starting merge process&#x27;);&#xA;      print(&#x27;Number of videos to merge: ${_recordedVideos.length}&#x27;);&#xA;      for (var i = 0; i &lt; _recordedVideos.length; i&#x2B;&#x2B;) {&#xA;        final file = File(_recordedVideos[i]);&#xA;        final exists = await file.exists();&#xA;        final size = exists ? await file.length() : 0;&#xA;        print(&#x27;Video $i: ${_recordedVideos[i]}&#x27;);&#xA;        print(&#x27;Exists: $exists, Size: $size bytes&#x27;);&#xA;      }&#xA;&#xA;      final Directory appDir = await getApplicationDocumentsDirectory();&#xA;      final String outputPath =&#xA;          &#x27;${appDir.path}/merged_${DateTime.now().millisecondsSinceEpoch}.mp4&#x27;;&#xA;      final String listFilePath = &#x27;${appDir.path}/list.txt&#x27;;&#xA;&#xA;      print(&#x27;Output path: $outputPath&#x27;);&#xA;      print(&#x27;List file path: $listFilePath&#x27;);&#xA;&#xA;      // Create and verify list file&#xA;      final listFile = File(listFilePath);&#xA;      final fileContent = _recordedVideos&#xA;          .map((path) => "file &#x27;${path.replaceAll("&#x27;", "&#x27;\\&#x27;&#x27;")}&#x27;")&#xA;          .join(&#x27;\n&#x27;);&#xA;      await listFile.writeAsString(fileContent);&#xA;&#xA;      print(&#x27;List file content:&#x27;);&#xA;      print(await listFile.readAsString());&#xA;&#xA;      // Simpler FFmpeg command for testing&#xA;      final command = &#x27;&#x27;&#x27;&#xA;      -f concat&#xA;      -safe 0&#xA;      -i "$listFilePath"&#xA;      -c copy&#xA;      -y&#xA;      "$outputPath"&#xA;    &#x27;&#x27;&#x27;&#xA;          .trim()&#xA;          .replaceAll(&#x27;\n&#x27;, &#x27; &#x27;);&#xA;&#xA;      print(&#x27;Executing FFmpeg command: $command&#x27;);&#xA;&#xA;      final session = await FFmpegKit.execute(command);&#xA;      final returnCode = await session.getReturnCode();&#xA;      final logs = await session.getAllLogsAsString();&#xA;      final failStackTrace = await session.getFailStackTrace();&#xA;&#xA;      print(&#x27;FFmpeg return code: ${returnCode?.getValue() ?? "null"}&#x27;);&#xA;      print(&#x27;FFmpeg logs: $logs&#x27;);&#xA;      if (failStackTrace != null) {&#xA;        print(&#x27;FFmpeg fail stack trace: $failStackTrace&#x27;);&#xA;      }&#xA;&#xA;      if (ReturnCode.isSuccess(returnCode)) {&#xA;        final outputFile = File(outputPath);&#xA;        final outputExists = await outputFile.exists();&#xA;        final outputSize = outputExists ? await outputFile.length() : 0;&#xA;&#xA;        print(&#x27;Output file exists: $outputExists&#x27;);&#xA;        print(&#x27;Output file size: $outputSize bytes&#x27;);&#xA;&#xA;        if (outputExists &amp;&amp; outputSize > 0) {&#xA;          setState(() => _recordedVideos.add(outputPath));&#xA;          _showSuccess(&#x27;Videos merged successfully&#x27;);&#xA;        } else {&#xA;          _showError(&#x27;Merged file is empty or not created&#x27;);&#xA;        }&#xA;      } else {&#xA;        _showError(&#x27;Failed to merge videos. Check logs for details.&#x27;);&#xA;      }&#xA;&#xA;      // Clean up&#xA;      try {&#xA;        await listFile.delete();&#xA;        print(&#x27;List file cleaned up successfully&#x27;);&#xA;      } catch (e) {&#xA;        print(&#x27;Failed to delete list file: $e&#x27;);&#xA;      }&#xA;    } catch (e, s) {&#xA;      print(&#x27;Error during merge: $e&#x27;);&#xA;      print(&#x27;Stack trace: $s&#x27;);&#xA;      _showError(&#x27;Error merging videos: ${e.toString()}&#x27;);&#xA;    }&#xA;  }&#xA;&#xA;  void _showError(String message) {&#xA;    ScaffoldMessenger.of(context).showSnackBar(&#xA;      SnackBar(content: Text(message), backgroundColor: Colors.red),&#xA;    );&#xA;  }&#xA;&#xA;  void _showSuccess(String message) {&#xA;    ScaffoldMessenger.of(context).showSnackBar(&#xA;      SnackBar(content: Text(message), backgroundColor: Colors.green),&#xA;    );&#xA;  }&#xA;&#xA;  Future<void> _startAudioRecording() async {&#xA;    try {&#xA;      final Directory tempDir = await getTemporaryDirectory();&#xA;      final audioPath = &#x27;${tempDir.path}/recording.wav&#x27;;&#xA;      await _audioRecorder.start(const RecordConfig(), path: audioPath);&#xA;      setState(() => _isRecording = true);&#xA;    } catch (e) {&#xA;      _showError(&#x27;Recording start error: $e&#x27;);&#xA;    }&#xA;  }&#xA;&#xA;  Future<void> _startVideoRecording() async {&#xA;    try {&#xA;      await _cameraController!.startVideoRecording();&#xA;      setState(() => _isRecording = true);&#xA;    } catch (e) {&#xA;      _showError(&#x27;Recording start error: $e&#x27;);&#xA;    }&#xA;  }&#xA;&#xA;  Future<void> _stopAndSaveAudioRecording() async {&#xA;    _audioPath = await _audioRecorder.stop();&#xA;    if (_audioPath != null) {&#xA;      final Directory appDir = await getApplicationDocumentsDirectory();&#xA;      final timestamp = DateTime.now().millisecondsSinceEpoch;&#xA;      final String audioFileName = &#x27;audio_$timestamp.wav&#x27;;&#xA;      await File(_audioPath!).copy(&#x27;${appDir.path}/$audioFileName&#x27;);&#xA;      _showSuccess(&#x27;Saved: $audioFileName&#x27;);&#xA;    }&#xA;  }&#xA;&#xA;  Future<void> _stopAndSaveVideoRecording() async {&#xA;    try {&#xA;      final video = await _cameraController!.stopVideoRecording();&#xA;      _videoPath = video.path;&#xA;&#xA;      if (_videoPath != null) {&#xA;        final Directory appDir = await getApplicationDocumentsDirectory();&#xA;        final timestamp = DateTime.now().millisecondsSinceEpoch;&#xA;        final String videoFileName = &#x27;video_$timestamp.mp4&#x27;;&#xA;        final savedVideoPath = &#x27;${appDir.path}/$videoFileName&#x27;;&#xA;        await File(_videoPath!).copy(savedVideoPath);&#xA;&#xA;        setState(() {&#xA;          _recordedVideos.add(savedVideoPath);&#xA;          _isRecording = false;&#xA;        });&#xA;&#xA;        _showSuccess(&#x27;Saved: $videoFileName&#x27;);&#xA;      }&#xA;    } catch (e) {&#xA;      _showError(&#x27;Recording stop error: $e&#x27;);&#xA;    }&#xA;  }&#xA;&#xA;  Future<void> _switchCamera() async {&#xA;    if (_cameras.length &lt;= 1) return;&#xA;&#xA;    if (_isRecording) {&#xA;      await _stopAndSaveVideoRecording();&#xA;      _currentCameraIndex = (_currentCameraIndex &#x2B; 1) % _cameras.length;&#xA;      await _initializeCameraController(_cameras[_currentCameraIndex]);&#xA;      await _startVideoRecording();&#xA;    } else {&#xA;      _currentCameraIndex = (_currentCameraIndex &#x2B; 1) % _cameras.length;&#xA;      await _initializeCameraController(_cameras[_currentCameraIndex]);&#xA;    }&#xA;  }&#xA;&#xA;  Future<void> _toggleRecording() async {&#xA;    if (_cameraController == null) return;&#xA;&#xA;    if (_isRecording) {&#xA;      await _stopAndSaveVideoRecording();&#xA;      await _stopAndSaveAudioRecording();&#xA;    } else {&#xA;      _startVideoRecording();&#xA;      _startAudioRecording();&#xA;      setState(() => _recordedVideos.clear());&#xA;    }&#xA;  }&#xA;}&#xA;</void></void></void></void></void></void></void></void></void></string></cameradescription></mergevideorecording></mergevideorecording>

    &#xA;

  • How do I get ffmpeg.exe to function on a cloud hosting site like Discloud ?

    16 septembre 2023, par Sc4rl3ttfir3

    So to keep my Discord bot running 24/7, I use the hosting site Discloud. I just added music playing capabilities to my bot, and they function fine when I run the bot locally, because it can access the .exe file for ffmpeg through the file path I have put in the code through the play command.

    &#xA;

    Code :

    &#xA;

    @bot.command(name=&#x27;play&#x27;, help=&#x27;To play song&#x27;)&#xA;async def play(ctx, url):&#xA;    voice_channel = ctx.author.voice.channel&#xA;&#xA;    if voice_channel is None:&#xA;        return await ctx.send(&#x27;You are not connected to a voice channel.&#x27;)&#xA;&#xA;    async with ctx.typing():&#xA;        filename = await YTDLSource.from_url(url, loop=bot.loop)&#xA;        &#xA;        if ctx.voice_client is not None:&#xA;            ctx.voice_client.stop()&#xA;&#xA;        source = discord.FFmpegPCMAudio(&#xA;            executable="C:\\Users\\Scarlett Rivera\\Documents\\ffmpeg\\ffmpeg.exe",&#xA;            source=filename&#xA;        )&#xA;        &#xA;        voice_channel.play(source)&#xA;&#xA;    await ctx.send(&#x27;**Now playing:** {}&#x27;.format(filename))&#xA;

    &#xA;

    However, whenever I try to use the play command while the bot is running through Discloud, it gives me this error in the logs :

    &#xA;

    Traceback (most recent call last):&#xA;File "/usr/local/lib/python3.11/site-packages/discord/ext/commands/core.py", line 235, in wrapped&#xA;ret = await coro(*args, **kwargs)&#xA;^^^^^^^^^^^^^^^^^^^^^^^^^^^&#xA;File "/home/user_686208406444572830/Sc4rl3ttb0t.py", line 351, in play&#xA;source = discord.FFmpegPCMAudio(&#xA;^^^^^^^^^^^^^^^^^^^^^^^&#xA;File "/usr/local/lib/python3.11/site-packages/discord/player.py", line 290, in __init__&#xA;super().__init__(source, executable=executable, args=args, **subprocess_kwargs)&#xA;File "/usr/local/lib/python3.11/site-packages/discord/player.py", line 166, in __init__&#xA;self._process = self._spawn_process(args, **kwargs)&#xA;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^&#xA;File "/usr/local/lib/python3.11/site-packages/discord/player.py", line 183, in _spawn_process&#xA;raise ClientException(executable &#x2B; &#x27; was not found.&#x27;) from None&#xA;discord.errors.ClientException: C:\Users\Scarlett Rivera\Documents\ffmpeg\ffmpeg.exe was not found.&#xA;  &#xA;The above exception was the direct cause of the following exception:&#xA; &#xA;Traceback (most recent call last):&#xA;File "/usr/local/lib/python3.11/site-packages/discord/ext/commands/bot.py", line 1350, in invoke&#xA;await ctx.command.invoke(ctx)&#xA;File "/usr/local/lib/python3.11/site-packages/discord/ext/commands/core.py", line 1029, in invoke&#xA;await injected(*ctx.args, **ctx.kwargs)  # type: ignore&#xA;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^&#xA;File "/usr/local/lib/python3.11/site-packages/discord/ext/commands/core.py", line 244, in wrapped&#xA;raise CommandInvokeError(exc) from exc&#xA;discord.ext.commands.errors.CommandInvokeError: Command raised an exception: ClientException: C:\Users\Scarlett Rivera\Documents\ffmpeg\ffmpeg.exe was not found.&#xA;

    &#xA;

    I've tried reaching out to another programmer who helped me yesterday with programming my bot to fulfill the main purpose I wanted from it, and they weren't able to come up with anything because they don't have any experience with Discloud. If anyone at all could help me, that would be extremely appreciated

    &#xA;

  • Xuggle - Concatenate two videos - Error - java.lang.RuntimeException : error -1094995529 decoding audio

    1er avril 2013, par user2232357

    I am using the Xuggle API to concatenate two MPEG videos (with Audio inbuilt in the MPEGs).
    I am referring to the https://code.google.com/p/xuggle/source/browse/trunk/java/xuggle-xuggler/src/com/xuggle/mediatool/demos/ConcatenateAudioAndVideo.java?r=929. (my both inputs and output are MPEGs).

    Getting the bellow error.

    14:06:50.139 [main] ERROR org.ffmpeg - [mp2 @ 0x7fd54693d000] incomplete frame
    java.lang.RuntimeException: error -1094995529 decoding audio
       at com.xuggle.mediatool.MediaReader.decodeAudio(MediaReader.java:549)
       at com.xuggle.mediatool.MediaReader.readPacket(MediaReader.java:469)
       at com.tav.factory.video.XuggleMediaCreator.concatenateAllVideos(XuggleMediaCreator.java:271)
       at com.tav.factory.video.XuggleMediaCreator.main(XuggleMediaCreator.java:446)

    Can anyone help mw with this ??? Thanks in Advance..

    Here is the complete code.

    public String concatenateAllVideos(ArrayList<tavtexttoavrequest> list){
           String finalPath="";


           String sourceUrl1 = "/Users/SSID/WS/SampleTTS/page2/AV_TAVImage2.mpeg";
           String sourceUrl2 = "/Users/SSID/WS/SampleTTS/page2/AV_TAVImage3.mpeg";
           String destinationUrl = "/Users/SSID/WS/SampleTTS/page2/z_AV_TAVImage_Final23.mpeg";

           out.printf("transcode %s + %s -> %s\n", sourceUrl1, sourceUrl2,
             destinationUrl);

           //////////////////////////////////////////////////////////////////////
           //                                                                  //
           // NOTE: be sure that the audio and video parameters match those of //
           // your input media                                                 //
           //                                                                  //
           //////////////////////////////////////////////////////////////////////

           // video parameters

           final int videoStreamIndex = 0;
           final int videoStreamId = 0;
           final int width = 400;
           final int height = 400;

           // audio parameters

           final int audioStreamIndex = 1;
           final int audioStreamId = 0;
           final int channelCount = 1;
           final int sampleRate = 16000 ; // Hz 16000 44100;

           // create the first media reader

           IMediaReader reader1 = ToolFactory.makeReader(sourceUrl1);

           // create the second media reader

           IMediaReader reader2 = ToolFactory.makeReader(sourceUrl2);

           // create the media concatenator

           MediaConcatenator concatenator = new MediaConcatenator(audioStreamIndex,
             videoStreamIndex);

           // concatenator listens to both readers

           reader1.addListener(concatenator);
           reader2.addListener(concatenator);

           // create the media writer which listens to the concatenator

           IMediaWriter writer = ToolFactory.makeWriter(destinationUrl);
           concatenator.addListener(writer);

           // add the video stream

           writer.addVideoStream(videoStreamIndex, videoStreamId, width, height);

           // add the audio stream

           writer.addAudioStream(audioStreamIndex, audioStreamId, channelCount,sampleRate);

           // read packets from the first source file until done

           try {
               while (reader1.readPacket() == null)
                 ;
           } catch (Exception e) {
               // TODO Auto-generated catch block
               e.printStackTrace();
           }

           // read packets from the second source file until done

           try {
               while (reader2.readPacket() == null)
                 ;
           } catch (Exception e) {
               // TODO Auto-generated catch block
               e.printStackTrace();
           }

           // close the writer

           writer.close();


           return finalPath;
       }

       static class MediaConcatenator extends MediaToolAdapter
         {
           // the current offset

           private long mOffset = 0;

           // the next video timestamp

           private long mNextVideo = 0;

           // the next audio timestamp

           private long mNextAudio = 0;

           // the index of the audio stream

           private final int mAudoStreamIndex;

           // the index of the video stream

           private final int mVideoStreamIndex;

           /**
            * Create a concatenator.
            *
            * @param audioStreamIndex index of audio stream
            * @param videoStreamIndex index of video stream
            */

           public MediaConcatenator(int audioStreamIndex, int videoStreamIndex)
           {
             mAudoStreamIndex = audioStreamIndex;
             mVideoStreamIndex = videoStreamIndex;
           }

           public void onAudioSamples(IAudioSamplesEvent event)
           {
             IAudioSamples samples = event.getAudioSamples();

             // set the new time stamp to the original plus the offset established
             // for this media file

             long newTimeStamp = samples.getTimeStamp() + mOffset;

             // keep track of predicted time of the next audio samples, if the end
             // of the media file is encountered, then the offset will be adjusted
             // to this time.

             mNextAudio = samples.getNextPts();

             // set the new timestamp on audio samples

             samples.setTimeStamp(newTimeStamp);

             // create a new audio samples event with the one true audio stream
             // index

             super.onAudioSamples(new AudioSamplesEvent(this, samples,
               mAudoStreamIndex));
           }

           public void onVideoPicture(IVideoPictureEvent event)
           {
             IVideoPicture picture = event.getMediaData();
             long originalTimeStamp = picture.getTimeStamp();

             // set the new time stamp to the original plus the offset established
             // for this media file

             long newTimeStamp = originalTimeStamp + mOffset;

             // keep track of predicted time of the next video picture, if the end
             // of the media file is encountered, then the offset will be adjusted
             // to this this time.
             //
             // You&#39;ll note in the audio samples listener above we used
             // a method called getNextPts().  Video pictures don&#39;t have
             // a similar method because frame-rates can be variable, so
             // we don&#39;t now.  The minimum thing we do know though (since
             // all media containers require media to have monotonically
             // increasing time stamps), is that the next video timestamp
             // should be at least one tick ahead.  So, we fake it.

             mNextVideo = originalTimeStamp + 1;

             // set the new timestamp on video samples

             picture.setTimeStamp(newTimeStamp);

             // create a new video picture event with the one true video stream
             // index

             super.onVideoPicture(new VideoPictureEvent(this, picture,
               mVideoStreamIndex));
           }

           public void onClose(ICloseEvent event)
           {
             // update the offset by the larger of the next expected audio or video
             // frame time

             mOffset = Math.max(mNextVideo, mNextAudio);

             if (mNextAudio &lt; mNextVideo)
             {
               // In this case we know that there is more video in the
               // last file that we read than audio. Technically you
               // should pad the audio in the output file with enough
               // samples to fill that gap, as many media players (e.g.
               // Quicktime, Microsoft Media Player, MPlayer) actually
               // ignore audio time stamps and just play audio sequentially.
               // If you don&#39;t pad, in those players it may look like
               // audio and video is getting out of sync.

               // However kiddies, this is demo code, so that code
               // is left as an exercise for the readers. As a hint,
               // see the IAudioSamples.defaultPtsToSamples(...) methods.
             }
           }

           public void onAddStream(IAddStreamEvent event)
           {
             // overridden to ensure that add stream events are not passed down
             // the tool chain to the writer, which could cause problems
           }

           public void onOpen(IOpenEvent event)
           {
             // overridden to ensure that open events are not passed down the tool
             // chain to the writer, which could cause problems
           }

           public void onOpenCoder(IOpenCoderEvent event)
           {
             // overridden to ensure that open coder events are not passed down the
             // tool chain to the writer, which could cause problems
           }

           public void onCloseCoder(ICloseCoderEvent event)
           {
             // overridden to ensure that close coder events are not passed down the
             // tool chain to the writer, which could cause problems
           }
         }
    </tavtexttoavrequest>