Open mondain opened 3 years ago
My main focus in writing the library was on metadata, the audio support was mostly just for copying between files when changing metadata. That means functionality and examples in the area you want to use is lacking, sorry!
I think you need to be creating a new OpusAudioData for every few encoded samples, from bytes, and writing them individually. That way, the granule positions should get calculated for you.
Only create via packets if the encoder is doing the framing stuff for you, and giving you the granule data, in which case you'd also need to record the granule info on the packet before you wrap as AudioData
@Gagravarr thanks for the info; I was wondering what the heck I was doing wrong. I'll check my encoded bytes and see if there is information in there; I'm not super familiar with the Opus byte stream at a low level yet.
@mondain Opus works on a frame level, one frame usually 20ms. This data is packaged into the Ogg container format. See the RFC section 3 (https://tools.ietf.org/html/rfc6716#section-3) , it explains how it is done. If you have encoded Opus frames, you can use this library to generate an Opus file. Encoding PCM is beyond the scope of this library.
I've added a unit test for opus which adds audio data to a new file, a moderate amount of data at a time (to mostly replicate a frame), after a bug fix it seems to be working - https://github.com/Gagravarr/VorbisJava/blob/67bdd7b125207c4527d7bfeed7a7d75d366c7d86/core/src/test/java/org/gagravarr/opus/TestOpusFileWrite.java#L221
@Gagravarr awesome! Thanks for that new test; I was just reading through the RFC sections that @andrm had posted earlier.
If you wanted to add actual opus encode of dummy pcm values, there is a pure java opus encoder here without any JNI requirements. Your unit test helped me figure out what I had done wrong, I was providing too much data to the opus file and not utilizing my offset value.
@mondain Thanks for the link, I didn't know about that!
I thought it might be found as interesting, I learned of it just recently as well; I'm using the official opus native stuff via JNI for regular work.
I pasted an opus encoded tone as hex strings to this file https://pastebin.com/jPRiwELv Its from a source that I'm testing with. When I write it to opus, it has a blip or click after what I think is each OpusAudioData
write, but I'm not sure where its being introduced yet. I'll write a unit test and put it in a PR today, maybe someone can help me sort it out. I've linked the output files here https://www.dropbox.com/sh/hyehy3agw05hamj/AAAWrv_3VjRgMKRh0OSqelr6a?dl=0 out.opus is the opus output of course, out.wav is the AAC version.
Sorry, I don't have time to look at it. Please use opusinfo from the opus utilities with your generated file, it will tell you if something went wrong.
@Gagravarr and @andrm don't misunderstand me, I appreciate your assistance with my reports; I also maintain a few projects so I've been on the other end of this; I demand nothing, if you are able to assist then that's super! If not, no big deal, I'll dig in as needed.
I fixed a unit test bug in TestOpusFileWriter, I'll have a PR by EOD today for you guys to have a look at; also "resolved" the javadoc issue by fixing some of the tags and setting a configuration option on the plugin itself.
Added my PR https://github.com/Gagravarr/VorbisJava/pull/41
I suspect there's an issue when writing to the opus file for stereo content. My source is 00:00:01.00 long and 3001 160 byte chunks; once written it shows up as 00:00:01.56 long (with ffprobe). I ran the file through opus tool, it prints a bunch of granule error/warn items; I'm not sure what to make of the output:
New logical stream 72cf (29391) found
Processing file "../core/target/test-classes/out.opus"
Opus Headers:
Version: 1
Vendor: Gagravarr.org Java Vorbis Tools v0.8 20160217
Channels: 2
Rate: 48000Hz
Pre-Skip: 120
Playback Gain: 0dB
User Comments:
title=Test Dummy Audio
WARNING: Sample count ahead granule (146880<0) in stream29391
WARNING: Sample count ahead granule (245760<0) in stream29391
WARNING: Sample count ahead granule (344640<0) in stream29391
WARNING: Sample count ahead granule (443520<0) in stream29391
WARNING: Sample count ahead granule (542400<0) in stream29391
WARNING: Sample count ahead granule (641280<0) in stream29391
WARNING: Sample count ahead granule (740160<0) in stream29391
WARNING: Sample count ahead granule (839040<0) in stream29391
WARNING: Sample count ahead granule (937920<0) in stream29391
WARNING: Sample count ahead granule (1036800<0) in stream29391
WARNING: Sample count ahead granule (1135680<0) in stream29391
WARNING: Sample count ahead granule (1234560<0) in stream29391
WARNING: Sample count ahead granule (1333440<0) in stream29391
WARNING: Sample count ahead granule (1432320<0) in stream29391
WARNING: Sample count ahead granule (1531200<0) in stream29391
WARNING: Sample count ahead granule (1630080<0) in stream29391
WARNING: Sample count ahead granule (1728960<0) in stream29391
WARNING: Sample count ahead granule (1827840<0) in stream29391
WARNING: Sample count ahead granule (1926720<0) in stream29391
WARNING: Sample count ahead granule (2025600<0) in stream29391
WARNING: Sample count ahead granule (2124480<0) in stream29391
WARNING: Sample count ahead granule (2223360<0) in stream29391
WARNING: Sample count ahead granule (2322240<0) in stream29391
WARNING: Sample count ahead granule (2421120<0) in stream29391
WARNING: Sample count ahead granule (2520000<0) in stream29391
WARNING: Sample count ahead granule (2618880<0) in stream29391
WARNING: Sample count ahead granule (2717760<0) in stream29391
Logical stream 72cf (29391) completed
Opus Audio:
Total Data Packets: 3001
Total Data Length: 480160
Audio Length Seconds: 1.5575
Audio Length: 00:00:01.56
Packet duration: 20.0ms (max), 20.0ms (avg), 20.0ms (min)
Page duration: 3400.0ms (max), 2069.7ms (avg), 1000.0ms (min)
Total data length: 480160 (overhead: 0.64%)
Playback length: 00:00:01.56
Average bitrate: 2.37 mb/s, w/o overhead: 2.35 mb/s (hard-CBR)
Also I've tried with preskip of 0 or 120, doesn't seem to matter.
@mondain Please see https://tools.ietf.org/html/rfc7845.html on how to calculate granule position and pre-skip.
core/src/main/java/org/gagravarr/opus/OpusStatistics.java has also instructive code, you see where the errors are coming from.
@andrm I pulled the PR https://github.com/Gagravarr/VorbisJava/pull/33 into my fork and the granule warnings disappeared and the duration is exactly correct now in ffprobe and opustool Playback length: 00:01:00.00
@mondain do you think you could post a more complete solution to your issue? From what I gathered I'm trying to do the same thing and I tried using Vorbis in the same way you're doing and it's not working. See also my post here
thanks
I also encounter this problem. I can encode a pcm file for each sub byte array to opus byte array. Those encoded byte array are merged into one big byte array and saved a file. When encoding, I also recorded the relationship from original size to encoded size. ex: 320 byte to 17 byte. With that relationship. I can decode the 17 byte to original 320 byte.
However, the opusfile requires a magic header. I don't not know how to add header for the merged encoded byte array. The mergedByteArray size is 25200 and the size of output file with the following code is 25435.
File file = new File(fileFolder + filename + ".opus");
FileOutputStream outputStream = new FileOutputStream(file);
OpusInfo info = new OpusInfo();
info.setNumChannels(1);
info.setSampleRate(16000);
OpusTags tags = new OpusTags();
OpusFile oFile = new OpusFile(outputStream, info, tags);
OpusAudioData data = new OpusAudioData(mergedByteArray);
oFile.writeAudioData(data);
oFile.close();
I upload the output file into https://www.opusplayer.net/ and it cannot recognized my oupus file.
I have opus encoded bytes and I'd like to write them to an opus file; since the only example I found uses an existing opus file to read from then write to a new file, it doesn't fit my need. I don't have a source file, I am taking pcm samples and encoding them with an Opus encoder, so I tried to do this and it didn't work:
As well as this
When I tried using the OggPacket, I get this exception:
My file creation looks like so:
Any examples or clues as to how to accomplish what I need would be greatly appretiated.