I've written an Android app that (among other things) records videos, which are then uploaded to an AWS server.
On the server, I need to be able to determine the rotation of the videos. My research indicates that MP4Parser should be able to help me with that, but running:
FileDataSourceImpl fileDataSource = new FileDataSourceImpl("path/to/file");
IsoFile isoFile = new IsoFile(fileDataSource);
MovieBox moov = isoFile.getMovieBox();
for (Box b : moov.getBoxes()) {
System.out.println(b);
}
on my file gives me the following output:
MovieHeaderBox[creationTime=Wed Jun 15 12:08:38 IDT 2016;modificationTime=Wed Jun 15 12:08:38 IDT 2016;timescale=1000;duration=2057;rate=1.0;volume=1.0;matrix=Rotate 0°;nextTrackId=2]
UserDataBox[]
TrackBox[]
If, within my app, I run the following Android code on the very same file:
MediaMetadataRetriever m = new MediaMetadataRetriever();
m.setDataSource("path/to/file");
String rotation = m.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION);
System.out.println("Rotation is " + rotation);
I get:
06-15 12:07:36.741 27424-27424/... I/System.out: Rotation is 90
Why the discrepancy? And is there any pure Java (no native libraries) tool that I can use to get the same results on the server side, without the benefit of the native Android code?
Thanks,
Reuven
Related
I have a grayscale .mkv video, which i want to open with OpenCV in Java, but i get the following errors:
With return new VideoCapture(path, Videoio.CAP_FFMPEG);
Errors:
[ERROR:0#0.004] global /build/opencv/modules/videoio/src/cap_ffmpeg_impl.hpp (1108) open Could not find decoder for codec_id=61
[ERROR:0#0.004] global /build/opencv/modules/videoio/src/cap_ffmpeg_impl.hpp (1140) open VIDEOIO/FFMPEG: Failed to initialize VideoCapture
With return new VideoCapture(path, Videoio.CAP_DSHOW); No errors, but
video.isOpened() is false
With return new VideoCapture(path);
Errors:
[ERROR:0#0.005] global /build/opencv/modules/videoio/src/cap_ffmpeg_impl.hpp (1108) open Could not find decoder for codec_id=61
[ERROR:0#0.005] global /build/opencv/modules/videoio/src/cap_ffmpeg_impl.hpp (1140) open VIDEOIO/FFMPEG: Failed to initialize VideoCapture
[ WARN:0#0.122] global C:\build\master_winpack-bindings-win64-vc14-static\opencv\modules\videoio\src\cap_msmf.cpp (923) CvCapture_MSMF::initStream Failed to set mediaType (stream 0, (480x360 # 1) MFVideoFormat_RGB24(codec not found)
I have installed OpenCV and added it as a dependency using this video.
I have also tried adding ...\opencv\build\bin\opencv_videoio_ffmpeg455_64.dll to the native libraries, and also tried using this: System.load("path\\to\\opencv\\build\\bin\\opencv_videoio_ffmpeg455_64.dll");.
Full code:
public class Test {
static {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
System.load("path\\to\\opencv\\build\\bin\\opencv_videoio_ffmpeg455_64.dll");
}
public static void main(String[] args) {
List<Mat> frames = getVideoFrames(openVideoFile(args[0]));
System.out.println(frames.size());
}
}
//... different class
public static VideoCapture openVideoFile(String path) {
return new VideoCapture(path);
}
public static List<Mat> getVideoFrames(VideoCapture video) {
List<Mat> frames = new ArrayList<>();
Mat frame = new Mat();
if (video.isOpened()) {
while (video.read(frame)) {
frames.add(frame);
}
video.release();
}
return frames;
}
ffprobe result:
Metadata:
MAJOR_BRAND : qt
MINOR_VERSION : 512
COMPATIBLE_BRANDS: qt
ENCODER : Lavf56.40.101
Duration: 00:01:05.83, start: 0.000000, bitrate: 1511 kb/s
Stream #0:0(eng): Video: png (MPNG / 0x474E504D), rgb24(pc), 480x360 [SAR 1:1 DAR 4:3], 6 fps, 6 tbr, 1k tbn (default)
Metadata:
LANGUAGE : eng
HANDLER_NAME : DataHandler
ENCODER : Lavc56.60.100 png
DURATION : 00:01:05.834000000
The error message is indicating that OpenCV's FFmpeg plugin is not built with MPNG codec support. So, you are essentially SOL to get this task done only with OpenCV (you can request OpenCV to support the codec, but it won't be a quick adaption even if you succeed to convince their devs to do so). Here are a couple things I could think of as a non-Java/non-OpenCV person (I typically deal with Python/FFmpeg):
1a) If you have a control of the upstream of your data, change the video codec from MPNG to one with OpenCV support.
1b) Transcode the MKV file to re-encode the video stream with a supported codec within your program
Create a thread and call ffmpeg from Java as a subprocess (I think ProcessBuilder is the class you are interested in) and load the video data via stdout pipe. FFmpeg can be called in the following manner:
ffmpeg -i <video_path> -f rawvideo -pix_fmt gray -an -
The stdout pipe will receive 480x360 bytes per frame. Read as many frames as you need at a time. If you need to limit the frames, you need to do this in seconds using -ss, -t, and/or -to options.
I'm assuming this video is grayscale as you mentioned (ffprobe is indicating the video is saved in RGB format). If you need to get RGB, use -pix_fmt rgb24 and the video frame data.
Once you have the image data in memory, there should be an OpenCV function to create an image object from in-memory data.
In my akka project while I'm trying to build I am getting this error also I downloaded all libraries
Uncaught error from thread [PersistentActors-akka.persistence.dispatchers.default-plugin-dispatcher-5]: Could not load library. Reasons: [no leveldbjni64-1.8 in java.library.path, no leveldbjni-1.8 in java.library.path, no leveldbjni in java.library.path, /private/var/folders/52/md0sb9l50k3b8rxw4sclh7kh0000gn/T/libleveldbjni-64-1-498021637280856383.8: dlopen(/private/var/folders/52/md0sb9l50k3b8rxw4sclh7kh0000gn/T/libleveldbjni-64-1-498021637280856383.8, 1): no suitable image found. Did find:
/private/var/folders/52/md0sb9l50k3b8rxw4sclh7kh0000gn/T/libleveldbjni-64-1-498021637280856383.8: no matching architecture in universal wrapper
Could you help me so on windows I fixed this problem by downloading Microsoft Visual C++ 2010 Redistributable Package but on mac I am out of ideas
my code
class SimplePersistentActor extends PersistentActor with ActorLogging {
override def persistenceId: String = "simple-persistence"
override def receiveCommand: Receive = {
case message => log.info(s"Received: $message")
}
override def receiveRecover: Receive = {
case event => log.info(s"Recovered: $event")
}
}
val system = ActorSystem("Playground")
val simpleActor = system.actorOf(Props[SimplePersistentActor], "simplePersistentActor")
simpleActor ! "I love Akka!"
What am I doing?
I am writing a data analysis program in Java which relies on R´s arulesViz library to mine association rules.
What do I want?
My purpose is to store the rules in a String variable in Java so that I can process them later.
How does it work?
The code works using a combination of String.format and eval Java and RJava instructions respectively, being its behavior summarized as:
Given properly formatted Java data structures, creates a data frame in R.
Formats the recently created data frame into a transaction list using the arules library.
Runs the apriori algorithm with the transaction list and some necessary values passed as parameter.
Reorders the generated association rules.
Given that the association rules cannot be printed, they are written to the standard output with R´s write method, capture the output and store it in a variable. We have converted the association rules into a string variable.
We return the string.
The code is the following:
// Step 1
Rutils.rengine.eval("dataFrame <- data.frame(as.factor(c(\"Red\", \"Blue\", \"Yellow\", \"Blue\", \"Yellow\")), as.factor(c(\"Big\", \"Small\", \"Small\", \"Big\", \"Tiny\")), as.factor(c(\"Heavy\", \"Light\", \"Light\", \"Heavy\", \"Heavy\")))");
//Step 2
Rutils.rengine.eval("transList <- as(dataFrame, 'transactions')");
//Step 3
Rutils.rengine.eval(String.format("info <- apriori(transList, parameter = list(supp = %f, conf = %f, maxlen = 2))", supportThreshold, confidenceThreshold));
// Step 4
Rutils.rengine.eval("orderedRules <- sort(info, by = c('count', 'lift'), order = FALSE)");
// Step 5
REXP res = Rutils.rengine.eval("rulesAsString <- paste(capture.output(write(orderedRules, file = stdout(), sep = ',', quote = TRUE, row.names = FALSE, col.names = FALSE)), collapse='\n')");
// Step 6
return res.asString().replaceAll("'", "");
What´s wrong?
Running the code in Linux Will work perfectly, but when I try to run it in Windows, I get the following error referring to the return line:
Exception in thread "main" java.lang.NullPointerException
This is a common error I have whenever the R code generates a null result and passes it to Java. There´s no way to syntax check the R code inside Java, so whenever it´s wrong, this error message appears.
However, when I run the R code in brackets in the R command line in Windows, it works flawlessly, so both the syntax and the data flow are OK.
Technical information
In Linux, I am using R with OpenJDK 10.
In Windows, I am currently using Oracle´s latest JDK release, but trying to run the program with OpenJDK 12 for Windows does not solve anything.
Everything is 64 bits.
The IDE used in both operating systems is IntelliJ IDEA 2019.
Screenshots
Linux run configuration:
Windows run configuration:
I'm making a player that can play an MPEG-TS stream and display all its videos at once (for monitoring purposes) in one frame using Xuggler for JAVA.
My problem is getting to determine what programs this stream holds (tv programs) and what are its streams...
for example : audio stream 1 and video stream 3 belong to program "BBC".
Now I already got it working for a .ts file by using MediaInfo http://mediaarea.net/en/MediaInfo/ like so :
MediaInfo.exe -LogFile="log.txt" "some .ts file" .... which logs a file like this :
Menu #2
ID : 1001 (0x3E9)
Menu ID : 1202 (0x4B2)
Duration : 13mn 33s
List : 2001 (0x7D1) (MPEG Video) / 3002 (0xBBA) (MPEG Audio, English)
Language : / English
Service name : NBN
Service provider : NILESAT
Service type : digital television
UTC 2006-03-28 00:00:00 : en:NBN / en:Nilesat / / / 99:00:00 / Running
and then I parsed the file in java
but I need to make this work for a live stream and when I give MediaInfo a URL instead of a file it gives this error :
Libcurl library not found
I also tried vlc commands but turns out it doesn't have this option and only available in gui (show codec information)...
the player is already working and I got an extractor too... just need this media info to work... any ideas?
EDIT : I found out FFprobe which is bundled with FFmpeg http://www.ffmpeg.org/ can do the task
but for some reason I can't read anything from the input stream.
Here's what the output looks like:
Input #0, mpegts, from 'D:\record ts\PBR_REC_20140426094852_484.ts':
Duration: N/A, start: 6164.538011, bitrate: N/A
Program 1201
Metadata:
service_name : Arabica TV
service_provider: Nilesat
Stream #0:10[0x7db]: Video: mpeg2video (Main) ([2][0][0][0] / 0x0002), yuv42
0p(tv), 720x576 [SAR 16:15 DAR 4:3], max. 2348 kb/s, 25 fps, 25 tbr, 90k tbn, 50
tbc
Stream #0:4[0xbcf]: Audio: mp2, 48000 Hz, stereo, s16p, 384 kb/s
Program 1202
I tried this in JAVA:
try {
Process process ;
Scanner sc;
ProcessBuilder processBuilder = new ProcessBuilder("C:\\Users\\vlatkozelka\\Desktop\\ffmpeg-20140623-git-ca35037-win64-static\\bin\\ffprobe.exe","-i",filename);
process=processBuilder.start();
sc=new Scanner(process.getInputStream());
process=processBuilder.start();
while(sc.hasNext()){
System.out.println(sc.nextLine());
}
} catch (IOException ex) {
Logger.getLogger(ChannelDivider.class.getName()).log(Level.SEVERE, null, ex);
}
but the sc.hasNext() just hangs like there is no input
then I tried writing to a file with cmd by using > but it gave me a blank file
however trying both methods with FFprobe -h (help command) does give output which is very much confusing me, I see output in cmd but cant read it...
I just solved this, and hope someone might make use of it:
it turns out that FFprobe was writing to stderr, not stdout,
so instead of:
getInputStream()
I used:
getErrorStream()
Now all I have to do is parse that :)
Good morning,
I developed an application on Android through the Delphi XE5 which tries to save a text file in a shared folder on the server (windows) but I received the message I / O error 30. I've tried several ways in Assign File as describe in the code. Could help?
function gravar_registro():integer;
var NomeArqTxt: TextFile;
begin
try
begin
// AssignFile(NomeArqTxt, '/storage/sdcard1/FolderTEST/xxx.txt'); // Test1 OK = This is possible = OK = SDCARD
// AssignFile(NomeArqTxt, '/sdcard/FolderTEST/gerados/xxx.txt'); // Test2 OK = This is possible = OK = memória interna;
// AssignFile(NomeArqTxt, '\\192.168.1.152\FolderSHARED\xxx.txt'); // Test3 = ERROR = I've done testing, but I / O error 30
// AssignFile(NomeArqTxt, 'smb://192.168.1.152/FolderSHARED/xxx.txt'); // Test4 = ERROR = I've done testing, but I / O error 30
// AssignFile(NomeArqTxt, '192.168.1.152\FolderSHARED\xxx.txt'); // Test5 = ERROR = I've done testing, but I / O error 30
//. Observation: a) I've done testing with FolderSHARED folder and it has access to read / write
// b) The IP 192.168.1.152 is valid and active a personal computer on the internal network
{$I-}
Reset(NomeArqTxt);
{$I+}
if (IOResult <> 0) then
ReWrite(NomeArqTxt)
else
begin
CloseFile(NomeArqTxt);
Append(NomeArqTxt);
end;
Writeln(NomeArqTxt, 'TEST TEST TEST');
CloseFile(NomeArqTxt);
showmessage('File Saved...');
end
except
On Erro: Exception Do
begin
showmessage(Erro.Message);
end;
end;
end;
Use the TStringList object and then use it's TStringList.SaveToFile() function.
This is not possible without support for the network protocol used on the server side. For Windows, there is an Android library to support the SMB protocol. Some questions on Stackoverflow included source code which explain its usage and authentication with the server, for example:
Write/upload a file using Samba/JCIFS issue (SmbAuthException: Access is denied)
For an introduction see
http://durgemeister.wordpress.com/2014/04/26/mapping-a-network-with-jcifs-and-android/