I am trying to be able to pick out frames (video and metadata) from MPEG, MPEG-TS and MPEG-PS files and live streams (network / UDP / RTP streams). I was looking into using JCODEC to do this and I started off by trying to use the FrameGrab / FrameGrab8Bit classes, and ran into an error that those formats are "temporarily unsupported". I looked into going back some commits to see if I could just use older code, but it looks like both of those files have had those formats "temporarily unsupported" since 2013 / 2015, respectively.
I then tried to plug things back into the FrameGrab8Bit class by putting in the below code...
public static FrameGrab8Bit createFrameGrab8Bit(SeekableByteChannel in) throws IOException, JCodecException {
...
SeekableDemuxerTrack videoTrack = null;
...
case MPEG_PS:
MPSDemuxer psd = new MPSDemuxer(in);
List tracks = psd.getVideoTracks();
videoTrack = (SeekableDemuxerTrack)tracks.get(0);
break;
case MPEG_TS:
in.setPosition(0);
MTSDemuxer tsd = new MTSDemuxer(in);
ReadableByteChannel program = tsd.getProgram(481);
MPSDemuxer ptsd = new MPSDemuxer(program);
List<MPEGDemuxerTrack> tstracks = ptsd.getVideoTracks();
MPEGDemuxerTrack muxtrack = tstracks.get(0);
videoTrack = (SeekableDemuxerTrack)tstracks.get(0);
break;
...
but I ran into a packet header assertion failure in the MTSDemuxer.java class in the parsePacket function:
public static MTSPacket parsePacket(ByteBuffer buffer) {
int marker = buffer.get() & 0xff;
int marker = by & 0xff;
Assert.assertEquals(0x47, marker);
...
I found that when I reset the position of the seekable byte channel (i.e.: in.setPosition(0)) the code makes it past the assert, but then fails at videoTrack = (SeekableDemuxerTrack)tstracks.get(0) (tstracks.get(0) cannot be converted to a SeekableDemuxerTrack)
Am I waisting my time? Are these formats supported somewhere in the library and I am just not able to find them?
Also, after going around in the code and making quick test applications, it seems like all you get out of the demuxers are video frames. Is there no way to get the metadata frames associated with the video frames?
For reference, I am using the test files from: http://samples.ffmpeg.org/MPEG2/mpegts-klv/
In case anyone in the future also has this question. I got a response from a developer on the project's GitHub page to this question. Response:
Yeah, MPEG TS is not supported to the extent MP4 is. You can't really seek in TS streams (unless you index the entire stream before hand).
I also asked about how to implement the feature. I thought that it could be done by reworking the MTSDemuxer class to be built off of the SeekableDemuxerTrack so that things would be compatible with the FrameGrab8Bit class, and got the following response:
So it doesn't look like there's much sense to implement TS demuxer on top of SeekableDemuxerTrack. We haven't given much attention to TS demuxer actually, so any input is very welcome.
I think this (building the MTSDemuxer class off of the SeekableDemuxerTrack interface) would work for files (since you have everything already there). But without fully fleshing out that thought, I could not say for sure (it definitely makes sense that this solution would not work for a live MPEG-TS / PS connection).
Related
I am currentrly working on a Way to visualize Fractals in Java. The mathematics behind it work perfectly fine and I am very happy with how the Pics turn out. Now i want to take these Images and turn them into a Video. I've written a Java Program that produces any number of Pictures and saves them (alphabetically) in a new directory. Now I need a way for Java to convert these Images into a Video.
I know there are solutions such as ffmpeg, however I need this process to be repeatable, so I don't think a Command Line Application would be the best Option.
Is there any Way to implement such a function into Java directly ?
If you're willing to use a third party library and the platform is supported (Windows or Linux, 64bit). You can use Pilecv4j (Full disclosure, I'm the main committer).
There's a test checked in that does exactly this. You can find it here: TestSplitIntoFiles.java
Here is the pertinent function that does this with the minor difference that it's not reading the image file names from the contents on the disk:
private static void encodeFiles(final File imageDir, final long numFrames, final File outputVideo) throws IOException {
try(final CvMat firstFrame = ImageFile.readMatFromFile(new File(imageDir, "image-0.jpg").getAbsolutePath());
final EncodingContext ectx = Ffmpeg2.createEncoder()
.outputStream(outputVideo.getAbsolutePath())
.openVideoEncoder("libx264", "vidEncoder")
.addCodecOptions("preset", "slow")
.addCodecOptions("crf", "40")
.enable(firstFrame, false)
;) {
final VideoEncoder ve = ectx.getVideoEncoder("vidEncoder");
ectx.ready();
LongStream.range(0, numFrames)
.mapToObj(fn -> new File(imageDir, "image-" + fn + ".jpg").getAbsolutePath())
.forEach(frameFile -> {
try(CvMat mat = uncheck(() -> ImageFile.readMatFromFile(frameFile));) {
ve.encode(mat, false);
}
});
}
}
If you decide to give it a try, let me know if you run into any issues. You can use the Issues on GitHub. I've been using it professionally for a while.
Also, see the answer to this question: Read a mp4 and write to anther mp4 creates bigger size
I am making a file transfer system using Akka. I've been looking at the documents for a while. The current status of progress is Actor2 received the file sent by Actor1 and wrote it to the local system of Actor2 (Actor1 = sender, Actor2 = receiver).
But I couldn't find a way to know how much byte I received in real time when writing.
I tested it, and it turns out, with runWith API, files can be written locally. With runForeach API, how much byte was delivered in real time through. However, if these two are created at the same time, the file cannot be written.
Here's my simple source. Please give me some advice.
public static Behavior<Command> create() {
return Behaviors.setup(context -> {
context.getLog().info("Registering myself with receptionist");
context.getSystem().receptionist().tell(Receptionist.register(RECEIVER_SERVICE_KEY, context.getSelf().narrow()));
Materializer mat = Materializer.createMaterializer(context);
return Behaviors.receive(Command.class)
.onMessage(TransferFile.class, command -> {
command.sourceRef.getSource().runWith(FileIO.toPath(Paths.get("test.pptx")), mat);
//command.replyTo.tell(new FileTransfered("filename", 1024));
command.sourceRef.getSource().runForeach(f -> System.out.println(f.size()), mat);
return Behaviors.same();
}).build();
});
}
Use a BroadcastHub to allow multiple consumers of your Source:
Source<ByteString, NotUsed> fileSource = command.sourceRef.getSource();
RunnableGraph<Source<ByteString, NotUsed>> runnableGraph =
fileSource.toMat(BroadcastHub.of(ByteString.class, 256), Keep.right());
// adjust the buffer size (256) as needed
Source<ByteString, NotUsed> fromFileSource = runnableGraph.run(mat);
fromFileSource.runWith(FileIO.toPath(Paths.get("test.pptx")), mat);
fromFileSource.runForeach(f -> System.out.println(f.size()), mat);
BroadcastHub as suggested by Jeffrey, allows for a single running stream to be connected to multiple other streams that are started and stopped over time.
Having a stream that dynamically connects to others requires quite a lot of extra hoops internally, so if you don't need that it is better to avoid that overhead.
If you use case is rather that you want to consume a single source with two sinks that is better done with source.alsoTo(sink1).to(sink2).
alsoTo in the flow API is backed by the Broadcast operator, but using that directly requires that you use the Graph DSL.
I'm trying to create an SNMP4j agent and am finding it difficult to understand the process correctly. I have successfully created an agent that can be queried from the command line using snmpwalk. What I am having difficulty with is understanding how I am meant to update the values stored in my implemented MIB.
The following shows the relevant code I use for creating the MIB (I implement Host-Resources-MIB)
agent = new Agent("0.0.0.0/" + port);
agent.start();
agent.unregisterManagedObject(agent.getSnmpv2MIB());
modules = new Modules(DefaultMOFactory.getInstance());
HrSWRunEntryRow thisRow = modules.getHostResourcesMib().getHrSWRunEntry()
.createRow(oidHrSWRunEntry);
final OID ashEnterpriseMIB = new OID(".1.3.6.1.4.1.49266.0");
thisRow.setHrSWRunIndex(new Integer32(1));
thisRow.setHrSWRunName(new OctetString("RunnableAgent"));
thisRow.setHrSWRunID(ashEnterpriseMIB);
thisRow.setHrSWRunPath(new OctetString("All is good in the world")); // Max 128 characters
thisRow.setHrSWRunParameters(new OctetString("Everything is working")); // Max 128 characters
thisRow.setHrSWRunType(new Integer32(HrSWRunTypeEnum.application));
thisRow.setHrSWRunStatus(new Integer32(HrSWRunStatusEnum.running));
modules.getHostResourcesMib().getHrSWRunEntry().addRow(thisRow);
agent.registerManagedObject(modules.getHostResourcesMib());
This appears to be sufficient to create a runnable agent. What I do not understand is how I am meant to change the values stored in the MIB (how do I, for example, change the value of HrSWRunStatus). There seem to be a few kludge ways but they don't seem to fit with the way the library is written.
I have come across numerous references to using/overriding the methods
prepare
commit
undo
cleanup
But cannot find any examples where this is done. Any help would be gratefully received.
In protected void registerManagedObjects(), you need to do something like new MOMutableColumn(columnId, SMIConstants.SYNTAX_INTEGER, MOAccessImpl.ACCESS_READ_WRITE, null); for your HrSWRunStatus. Take a look at the TestAgent.java example of SNMP4J-agent source.
I downloaded Calabash XML a couple of days back and got it working easily enough from the command prompt. I then tried to run it from Java code I noticed there was no API (e.g. the Calabash main method is massive with code calls to everywhere). To get it working was very messy as I had to copy huge chunks from the main method to a wrapper class, and divert from the System.out to a byte array output stream (and eventually into a String) i.e.
...
ByteArrayOutputStream baos = new ByteArrayOutputStream (); // declare at top
...
WritableDocument wd = null;
if (uri != null) {
URI furi = new URI(uri);
String filename = furi.getPath();
FileOutputStream outfile = new FileOutputStream(filename);
wd = new WritableDocument(runtime,filename,serial,outfile);
} else {
wd = new WritableDocument(runtime,uri,serial, baos); // new "baos" parameter
}
The performance seems really, really slow e.g. i ran a simple filter 1000 times ...
<p:filter>
<p:with-option name="select" select="'/result/meta-data/neighbors/document/title'" />
</p:filter>
On average each time took 17ms which doesn't seem like much but my spring REST controller with calls to Mongo DB and encryption calls etc take on average 3/4 ms.
Has anyone encountered this when running Calabash from code? Is there something I can do to speed things up?
For example, I this is being called each time -
XProcRuntime runtime = new XProcRuntime(config);
Can this be created once and reused? Any help is appreciated as I don't want to have to pay money to use Calamet but really want to get Xproc working from code to an acceptable performance.
For examples on how you could integrate XMLCalabash in a framework, I can mention Servlex by Florent Georges. You'd have to browse the code to find the relevant bit, but last time I looked it shouldn't be too hard to find:
http://servlex.net/
XMLCalabash wasn't build for speed unfortunately. I am sure that if you run profile, and can find some hotspots, Norm Walsh would be interested to hear about it.
Alternative is to look into Quixprox, which is derived from XMLCalabash:
https://code.google.com/p/quixproc/
I am also very sure that if you can send Norm a patch to improve the main class for better integration, he'd be interested to hear about it. In fact, the code should be on github, just fork it, fix it, and do a pull request..
HTH!
I need programmatically extract frames from mp4 video file, so each frame goes into a separate file. Please advise on a library that will allow to get result similar to the following VLC command (http://www.videolan.org/vlc/):
vlc v1.mp4 --video-filter=scene --vout=dummy --start-time=1 --stop-time=5 --scene-ratio=1 --scene-prefix=img- --scene-path=./images vlc://quit
Library for any of these Java / Python / Erlang / Haskell will do the job for me.
Consider using the following class by Popscan. The usage is as follows:
VideoSource vs = new VideoSource("file://c:\test.avi");
vs.initialize();
...
int frameIndex = 12345; // any frame
BufferedImage frame = vs.getFrame(frameIndex);
I would personally look for libraries that wrap ffmpeg/libavcodec (the understands-most-things library that many encoders and players use).
I've not really tried any yet so can't say anything about code quality and ease, but the five-line pyffmpeg example suggests it's an easy option - though it may well be *nix-only.