Streampunk / beamcoder

Node.js native bindings to FFmpeg.
GNU General Public License v3.0
400 stars 76 forks source link

muxer.writeFrame() with frame fails with "Function not implemented" #74

Open EmDubleYou opened 3 years ago

EmDubleYou commented 3 years ago

I'm trying to copy frames from an input to an output without re-encoding them for the purposes of datamoshing. I don't see anything obviously wrong with my code so I think it's either a bug or there's something I'm missing. I've tried this on Ubuntu 18.04. 20.04, and Windows 10 and it happens with all of them.

writeFrame() with a packet does work but working with frames instead of packets is much better for what I want to do and I don't see a way of getting frames back into a packet without re-encoding them, though I might be wrong about that.

const beamcoder = require('beamcoder')

async function run () {
  let dm = await beamcoder.demuxer('./test.mp4') //setup input file

  let vdecoder = beamcoder.decoder({ demuxer: dm, stream_index: 0 })
  let adecoder = beamcoder.decoder({ demuxer: dm, stream_index: 1 })

  mux = beamcoder.muxer({ filename: './output.mp4' }) //setup output file

  vstream = await mux.newStream(dm.streams[0])
  astream = await mux.newStream(dm.streams[1])

  await mux.openIO()
  await mux.writeHeader()

  let packet = await dm.read()
  while (packet != null) { //read input packets
    if (packet.stream_index === 0) { 
      res = await vdecoder.decode(packet) //decode frames
      if (res.frames.length > 0) {
        for (const frame in res.frames) { //write decoded frames to output
          await mux.writeFrame({ frame: res.frames[frame], stream_index: 0 }) //throws 5016 error
        }
      }
    } else if (packet.stream_index === 1) {
      res = await adecoder.decode(packet)
      if (res.frames.length > 0) {
        for (const frame in res.frames) {
          await mux.writeFrame({ frame: res.frames[frame], stream_index: 1 })
        }
      }
    }
    packet = await dm.read()
  }
  await mux.writeTrailer();
}

run();

This minimal example gives me the following error:

Using FFmpeg version 4.3.2-0york0~18.04
node:internal/process/promises:227
          triggerUncaughtException(err, true /* fromPromise */);
          ^

[Error: In file ../src/mux.cc on line 588, found error: Error writing frame: Function not implemented] {
  code: '5016'
}

I've uploaded a test video but I've tried several videos that's probably not the problem.

The error message seems to come from line 575 in mux.cc so I think the error is coming from ret = av_write_uncoded_frame(c->format, c->streamIndex, c->frame); on line 567. I haven't opened it in a debugger to confirm this though. I found this thread that mentions av_write_uncoded_frame throwing not implemented despite being implemented so it could be related but it's over my head at this point.

If I'm missing something or there's an alternative, I'd like to know. If it's a bug it'd be nice to fix since this functionality is shown in the examples.

Bahlinc-Dev commented 2 years ago

You are passing decoded frames to the muxer, which needs ENCODED frames. Just skip the decode step and go straight from demuxer to muxer.

await mux.writeFrame({ packet: packet })