Recherche avancée

Médias (0)

Mot : - Tags -/publication

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

Autres articles (38)

  • Use, discuss, criticize

    13 avril 2011, par

    Talk to people directly involved in MediaSPIP’s development, or to people around you who could use MediaSPIP to share, enhance or develop their creative projects.
    The bigger the community, the more MediaSPIP’s potential will be explored and the faster the software will evolve.
    A discussion list is available for all exchanges between users.

  • Des sites réalisés avec MediaSPIP

    2 mai 2011, par

    Cette page présente quelques-uns des sites fonctionnant sous MediaSPIP.
    Vous pouvez bien entendu ajouter le votre grâce au formulaire en bas de page.

  • MediaSPIP Player : problèmes potentiels

    22 février 2011, par

    Le lecteur ne fonctionne pas sur Internet Explorer
    Sur Internet Explorer (8 et 7 au moins), le plugin utilise le lecteur Flash flowplayer pour lire vidéos et son. Si le lecteur ne semble pas fonctionner, cela peut venir de la configuration du mod_deflate d’Apache.
    Si dans la configuration de ce module Apache vous avez une ligne qui ressemble à la suivante, essayez de la supprimer ou de la commenter pour voir si le lecteur fonctionne correctement : /** * GeSHi (C) 2004 - 2007 Nigel McNie, (...)

Sur d’autres sites (9545)

  • How to play and seek fragmented MP4 audio using MSE SourceBuffer ?

    29 juin 2024, par Stefan Falk

    Note :

    


    


    If you end up here, you might want to take a look at shaka-player and the accompanying shaka-streamer. Use it. Don't implement this yourself unless you really have to.

    


    


    I am trying for quite some time now to be able to play an audio track on Chrome, Firefox, Safari, etc. but I keep hitting brick walls. My problem is currently that I am just not able to seek within a fragmented MP4 (or MP3).

    


    At the moment I am converting audio files such as MP3 to fragmented MP4 (fMP4) and send them chunk-wise to the client. What I do is defining a CHUNK_DURACTION_SEC (chunk duration in seconds) and compute a chunk size like this :

    


    chunksTotal = Math.ceil(this.track.duration / CHUNK_DURATION_SEC);
chunkSize = Math.ceil(this.track.fileSize / this.chunksTotal);


    


    With this I partition the audio file and can fetch it entirely jumping chunkSize-many bytes for each chunk :

    


    -----------------------------------------
| chunk 1 | chunk 2 |   ...   | chunk n |
-----------------------------------------


    


    How audio files are converted to fMP4

    


    ffmpeg -i input.mp3 -acodec aac -b:a 256k -f mp4 \
       -movflags faststart+frag_every_frame+empty_moov+default_base_moof \
        output.mp4


    


    This seems to work with Chrome and Firefox (so far).

    


    How chunks are appended

    


    After following this example, and realizing that it's simply not working as it is explained here, I threw it away and started over from scratch. Unfortunately without success. It's still not working.

    


    The following code is supposed to play a track from the very beginning to the very end. However, I also need to be able to seek. So far, this is simply not working. Seeking will just stop the audio after the seeking event got triggered.

    


    The code

    


    /* Desired chunk duration in seconds. */&#xA;const CHUNK_DURATION_SEC = 20;&#xA;&#xA;const AUDIO_EVENTS = [&#xA;  &#x27;ended&#x27;,&#xA;  &#x27;error&#x27;,&#xA;  &#x27;play&#x27;,&#xA;  &#x27;playing&#x27;,&#xA;  &#x27;seeking&#x27;,&#xA;  &#x27;seeked&#x27;,&#xA;  &#x27;pause&#x27;,&#xA;  &#x27;timeupdate&#x27;,&#xA;  &#x27;canplay&#x27;,&#xA;  &#x27;loadedmetadata&#x27;,&#xA;  &#x27;loadstart&#x27;,&#xA;  &#x27;updateend&#x27;,&#xA;];&#xA;&#xA;&#xA;class ChunksLoader {&#xA;&#xA;  /** The total number of chunks for the track. */&#xA;  public readonly chunksTotal: number;&#xA;&#xA;  /** The length of one chunk in bytes */&#xA;  public readonly chunkSize: number;&#xA;&#xA;  /** Keeps track of requested chunks. */&#xA;  private readonly requested: boolean[];&#xA;&#xA;  /** URL of endpoint for fetching audio chunks. */&#xA;  private readonly url: string;&#xA;&#xA;  constructor(&#xA;    private track: Track,&#xA;    private sourceBuffer: SourceBuffer,&#xA;    private logger: NGXLogger,&#xA;  ) {&#xA;&#xA;    this.chunksTotal = Math.ceil(this.track.duration / CHUNK_DURATION_SEC);&#xA;    this.chunkSize = Math.ceil(this.track.fileSize / this.chunksTotal);&#xA;&#xA;    this.requested = [];&#xA;    for (let i = 0; i &lt; this.chunksTotal; i&#x2B;&#x2B;) {&#xA;      this.requested[i] = false;&#xA;    }&#xA;&#xA;    this.url = `${environment.apiBaseUrl}/api/tracks/${this.track.id}/play`;&#xA;  }&#xA;&#xA;  /**&#xA;   * Fetch the first chunk.&#xA;   */&#xA;  public begin() {&#xA;    this.maybeFetchChunk(0);&#xA;  }&#xA;&#xA;  /**&#xA;   * Handler for the "timeupdate" event. Checks if the next chunk should be fetched.&#xA;   *&#xA;   * @param currentTime&#xA;   *  The current time of the track which is currently played.&#xA;   */&#xA;  public handleOnTimeUpdate(currentTime: number) {&#xA;&#xA;    const nextChunkIndex = Math.floor(currentTime / CHUNK_DURATION_SEC) &#x2B; 1;&#xA;    const hasAllChunks = this.requested.every(val => !!val);&#xA;&#xA;    if (nextChunkIndex === (this.chunksTotal - 1) &amp;&amp; hasAllChunks) {&#xA;      this.logger.debug(&#x27;Last chunk. Calling mediaSource.endOfStream();&#x27;);&#xA;      return;&#xA;    }&#xA;&#xA;    if (this.requested[nextChunkIndex] === true) {&#xA;      return;&#xA;    }&#xA;&#xA;    if (currentTime &lt; CHUNK_DURATION_SEC * (nextChunkIndex - 1 &#x2B; 0.25)) {&#xA;      return;&#xA;    }&#xA;&#xA;    this.maybeFetchChunk(nextChunkIndex);&#xA;  }&#xA;&#xA;  /**&#xA;   * Fetches the chunk if it hasn&#x27;t been requested yet. After the request finished, the returned&#xA;   * chunk gets appended to the SourceBuffer-instance.&#xA;   *&#xA;   * @param chunkIndex&#xA;   *  The chunk to fetch.&#xA;   */&#xA;  private maybeFetchChunk(chunkIndex: number) {&#xA;&#xA;    const start = chunkIndex * this.chunkSize;&#xA;    const end = start &#x2B; this.chunkSize - 1;&#xA;&#xA;    if (this.requested[chunkIndex] == true) {&#xA;      return;&#xA;    }&#xA;&#xA;    this.requested[chunkIndex] = true;&#xA;&#xA;    if ((end - start) == 0) {&#xA;      this.logger.warn(&#x27;Nothing to fetch.&#x27;);&#xA;      return;&#xA;    }&#xA;&#xA;    const totalKb = ((end - start) / 1000).toFixed(2);&#xA;    this.logger.debug(`Starting to fetch bytes ${start} to ${end} (total ${totalKb} kB). Chunk ${chunkIndex &#x2B; 1} of ${this.chunksTotal}`);&#xA;&#xA;    const xhr = new XMLHttpRequest();&#xA;    xhr.open(&#x27;get&#x27;, this.url);&#xA;    xhr.setRequestHeader(&#x27;Authorization&#x27;, `Bearer ${AuthenticationService.getJwtToken()}`);&#xA;    xhr.setRequestHeader(&#x27;Range&#x27;, &#x27;bytes=&#x27; &#x2B; start &#x2B; &#x27;-&#x27; &#x2B; end);&#xA;    xhr.responseType = &#x27;arraybuffer&#x27;;&#xA;    xhr.onload = () => {&#xA;      this.logger.debug(`Range ${start} to ${end} fetched`);&#xA;      this.logger.debug(`Requested size:        ${end - start &#x2B; 1}`);&#xA;      this.logger.debug(`Fetched size:          ${xhr.response.byteLength}`);&#xA;      this.logger.debug(&#x27;Appending chunk to SourceBuffer.&#x27;);&#xA;      this.sourceBuffer.appendBuffer(xhr.response);&#xA;    };&#xA;    xhr.send();&#xA;  };&#xA;&#xA;}&#xA;&#xA;export enum StreamStatus {&#xA;  NOT_INITIALIZED,&#xA;  INITIALIZING,&#xA;  PLAYING,&#xA;  SEEKING,&#xA;  PAUSED,&#xA;  STOPPED,&#xA;  ERROR&#xA;}&#xA;&#xA;export class PlayerState {&#xA;  status: StreamStatus = StreamStatus.NOT_INITIALIZED;&#xA;}&#xA;&#xA;&#xA;/**&#xA; *&#xA; */&#xA;@Injectable({&#xA;  providedIn: &#x27;root&#x27;&#xA;})&#xA;export class MediaSourcePlayerService {&#xA;&#xA;  public track: Track;&#xA;&#xA;  private mediaSource: MediaSource;&#xA;&#xA;  private sourceBuffer: SourceBuffer;&#xA;&#xA;  private audioObj: HTMLAudioElement;&#xA;&#xA;  private chunksLoader: ChunksLoader;&#xA;&#xA;  private state: PlayerState = new PlayerState();&#xA;&#xA;  private state$ = new BehaviorSubject<playerstate>(this.state);&#xA;&#xA;  public stateChange = this.state$.asObservable();&#xA;&#xA;  private currentTime$ = new BehaviorSubject<number>(null);&#xA;&#xA;  public currentTimeChange = this.currentTime$.asObservable();&#xA;&#xA;  constructor(&#xA;    private httpClient: HttpClient,&#xA;    private logger: NGXLogger&#xA;  ) {&#xA;  }&#xA;&#xA;  get canPlay() {&#xA;    const state = this.state$.getValue();&#xA;    const status = state.status;&#xA;    return status == StreamStatus.PAUSED;&#xA;  }&#xA;&#xA;  get canPause() {&#xA;    const state = this.state$.getValue();&#xA;    const status = state.status;&#xA;    return status == StreamStatus.PLAYING || status == StreamStatus.SEEKING;&#xA;  }&#xA;&#xA;  public playTrack(track: Track) {&#xA;    this.logger.debug(&#x27;playTrack&#x27;);&#xA;    this.track = track;&#xA;    this.startPlayingFrom(0);&#xA;  }&#xA;&#xA;  public play() {&#xA;    this.logger.debug(&#x27;play()&#x27;);&#xA;    this.audioObj.play().then();&#xA;  }&#xA;&#xA;  public pause() {&#xA;    this.logger.debug(&#x27;pause()&#x27;);&#xA;    this.audioObj.pause();&#xA;  }&#xA;&#xA;  public stop() {&#xA;    this.logger.debug(&#x27;stop()&#x27;);&#xA;    this.audioObj.pause();&#xA;  }&#xA;&#xA;  public seek(seconds: number) {&#xA;    this.logger.debug(&#x27;seek()&#x27;);&#xA;    this.audioObj.currentTime = seconds;&#xA;  }&#xA;&#xA;  private startPlayingFrom(seconds: number) {&#xA;    this.logger.info(`Start playing from ${seconds.toFixed(2)} seconds`);&#xA;    this.mediaSource = new MediaSource();&#xA;    this.mediaSource.addEventListener(&#x27;sourceopen&#x27;, this.onSourceOpen);&#xA;&#xA;    this.audioObj = document.createElement(&#x27;audio&#x27;);&#xA;    this.addEvents(this.audioObj, AUDIO_EVENTS, this.handleEvent);&#xA;    this.audioObj.src = URL.createObjectURL(this.mediaSource);&#xA;&#xA;    this.audioObj.play().then();&#xA;  }&#xA;&#xA;  private onSourceOpen = () => {&#xA;&#xA;    this.logger.debug(&#x27;onSourceOpen&#x27;);&#xA;&#xA;    this.mediaSource.removeEventListener(&#x27;sourceopen&#x27;, this.onSourceOpen);&#xA;    this.mediaSource.duration = this.track.duration;&#xA;&#xA;    this.sourceBuffer = this.mediaSource.addSourceBuffer(&#x27;audio/mp4; codecs="mp4a.40.2"&#x27;);&#xA;    // this.sourceBuffer = this.mediaSource.addSourceBuffer(&#x27;audio/mpeg&#x27;);&#xA;&#xA;    this.chunksLoader = new ChunksLoader(&#xA;      this.track,&#xA;      this.sourceBuffer,&#xA;      this.logger&#xA;    );&#xA;&#xA;    this.chunksLoader.begin();&#xA;  };&#xA;&#xA;  private handleEvent = (e) => {&#xA;&#xA;    const currentTime = this.audioObj.currentTime.toFixed(2);&#xA;    const totalDuration = this.track.duration.toFixed(2);&#xA;    this.logger.warn(`MediaSource event: ${e.type} (${currentTime} of ${totalDuration} sec)`);&#xA;&#xA;    this.currentTime$.next(this.audioObj.currentTime);&#xA;&#xA;    const currentStatus = this.state$.getValue();&#xA;&#xA;    switch (e.type) {&#xA;      case &#x27;playing&#x27;:&#xA;        currentStatus.status = StreamStatus.PLAYING;&#xA;        this.state$.next(currentStatus);&#xA;        break;&#xA;      case &#x27;pause&#x27;:&#xA;        currentStatus.status = StreamStatus.PAUSED;&#xA;        this.state$.next(currentStatus);&#xA;        break;&#xA;      case &#x27;timeupdate&#x27;:&#xA;        this.chunksLoader.handleOnTimeUpdate(this.audioObj.currentTime);&#xA;        break;&#xA;      case &#x27;seeking&#x27;:&#xA;        currentStatus.status = StreamStatus.SEEKING;&#xA;        this.state$.next(currentStatus);&#xA;        if (this.mediaSource.readyState == &#x27;open&#x27;) {&#xA;          this.sourceBuffer.abort();&#xA;        }&#xA;        this.chunksLoader.handleOnTimeUpdate(this.audioObj.currentTime);&#xA;        break;&#xA;    }&#xA;  };&#xA;&#xA;  private addEvents(obj, events, handler) {&#xA;    events.forEach(event => obj.addEventListener(event, handler));&#xA;  }&#xA;&#xA;}&#xA;</number></playerstate>

    &#xA;

    Running it will give me the following output :

    &#xA;

    enter image description here

    &#xA;

    &#xA;

    Apologies for the screenshot but it's not possible to just copy the output without all the stack traces in Chrome.

    &#xA;

    &#xA;

    What I also tried was following this example and call sourceBuffer.abort() but that didn't work. It looks more like a hack that used to work years ago but it's still referenced in the docs (see "Example" -> "You can see something similar in action in Nick Desaulnier's bufferWhenNeeded demo ..").

    &#xA;

    case &#x27;seeking&#x27;:&#xA;  currentStatus.status = StreamStatus.SEEKING;&#xA;  this.state$.next(currentStatus);        &#xA;  if (this.mediaSource.readyState === &#x27;open&#x27;) {&#xA;    this.sourceBuffer.abort();&#xA;  } &#xA;  break;&#xA;

    &#xA;

    Trying with MP3

    &#xA;

    I have tested the above code under Chrome by converting tracks to MP3 :

    &#xA;

    ffmpeg -i input.mp3 -acodec aac -b:a 256k -f mp3 output.mp3&#xA;

    &#xA;

    and creating a SourceBuffer using audio/mpeg as type :

    &#xA;

    this.mediaSource.addSourceBuffer(&#x27;audio/mpeg&#x27;)&#xA;

    &#xA;

    I have the same problem when seeking.

    &#xA;

    The issue wihout seeking

    &#xA;

    The above code has another issue :

    &#xA;

    After two minutes of playing, the audio playback starts to stutter and comes to a halt prematurely. So, the audio plays up to a point and then it stops without any obvious reason.

    &#xA;

    For whatever reason there is another canplay and playing event. A few seconds after, the audio simply stops..

    &#xA;

    enter image description here

    &#xA;

  • Being able to read the current audio frame using ffmpeg and python

    5 novembre 2020, par LambChopsAndSauce

    Is there a way to be able to read your current position in an audio file using FFmpeg ?

    &#xA;

    I want to make it so my discord bot plays an audio clip and then on exit, it saves the current position and then when it rejoins the VC it can resume at that point. I know how to get it to resume at the correct time using -ss but I am not sure how to get the timestamp at the point ti leaves.&#xA;Any help would be appreciated :) !

    &#xA;

  • How to reconstruct h264 video from raw IpCam feed

    10 avril 2014, par andrew

    I captured a raw feed from an IpCam which is normally viewed in an ActiveX control.

    The feed seems to be riddled with some kind of proprietary h.264 meta data. I don't know much about the h.264 codec but from what I've read I don't think the data is standard. It looks like this :

    67 45 00 00 8D E0 28 00  1D 00 00 00 45 00 00 00   gE...à(.....E...  
    00 00 01 0E 6D 11 01 00  66 6B 59 00 00 04 00 00   ....m...fkY.....    

    The feed has a variable frame rate, maybe this data has something to do with that ?

    When I tried running through FFMpeg it didn't want to know, It just said :

    Invalid data found when processing input

    I tried removing the strange looking data with php like this :

    $vid= file_get_contents(&#39;1.264&#39;);
    $cleanedUp=preg_replace("/\x67\x45([^\xFF]{30})/", &#39;&#39;, $vid,-1,$count);
    echo $count;
    file_put_contents(&#39;2.264&#39;, $cleanedUp);

    I tried again with FFMpeg :

    ffmpeg -i 2.264 1.avi

    Looking a little better ; This time FFMpeg produces an avi file but it outputs a lot of errors in the process, Here is a few :

    [h264 @ 0x9f4fc00] corrupted macroblock 5 5 (total_coeff=-1)
    [h264 @ 0x9f4fc00] error while decoding MB 5 5
    [h264 @ 0x9f4fc00] slice type too large (32) at 5 5
    [h264 @ 0x9f4fc00] decode_slice_header error
    [h264 @ 0x9f4fc00] Cannot use next picture in error concealment
    [h264 @ 0x9f4fc00] concealing 1408 DC, 1408 AC, 1408 MV errors in P frame
    [h264 @ 0x9f50a80] left block unavailable for requested intra mode at 0 11
    [h264 @ 0x9f50a80] error while decoding MB 0 11
    [h264 @ 0x9f50a80] Cannot use next picture in error concealment
    [h264 @ 0x9f50a80] concealing 1149 DC, 1149 AC, 1149 MV errors in P frame
    frame=  115 fps= 26 q=15.2 size=     606kB time=00:00:09.58 bitrate= 517.7kbits/[h264 @ 0x9f50a80] corrupted macroblock 29 21 (total_coeff=-1)
    [h264 @ 0x9f50a80] error while decoding MB 29 21
    [h264 @ 0x9f50a80] Cannot use next picture in error concealment
    [h264 @ 0x9f50a80] concealing 680 DC, 680 AC, 680 MV errors in P frame

    The video plays, but its garbled and the speed is about 4x the correct rate. I guess because the variable frame rate data is missing ?

    I tried again with :

     ffmpeg -r 12 -i 2.264 1.avi

    Forcing the input frame rate to be 12 fps (approximately correct).

    The video plays at the correct speed now but it still looks horrible.

    Id really appreciate any help with this.

    Here is a link to the raw capture.

    Here is a link to the capture with the weird headers removed.

    Here is a link to avi produced by FFMpeg.