MediaCodec
とMediaMuxer
の助けを借りてビデオをエンコードします。結果として、私はmp4ビデオファイルを持っています。このmp4ファイルにメタデータ(時間を作成する)を設定するにはどうすればよいですか? MediaMetadataRetrieverはメタデータの読み取りのみ可能ですが、変更はできません。私はffmpegを使いたくない。私はmp4parserライブラリ(this class)を試しましたが、それは私のためには機能しません。メタデータをmp4に設定
4
A
答えて
3
generally supported specificationが存在しないため、MP4ファイルのメタデータを設定することは明確ではありませんが、ほとんどのビデオプレーヤーはAppleの仕様をサポートしています。
ここは(MetaDataInsert.java
サンプルに基づいて)MP4メタデータにタイトルや作成日を設定するコードです:
import com.coremedia.iso.IsoFile;
import com.coremedia.iso.boxes.*;
import com.coremedia.iso.boxes.apple.AppleItemListBox;
import com.googlecode.mp4parser.boxes.apple.AppleNameBox;
import com.googlecode.mp4parser.boxes.apple.AppleRecordingYear2Box;
import com.googlecode.mp4parser.util.Path;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.util.List;
public class Mp4MetadataWriter {
public FileChannel splitFileAndInsert(File f, long pos, long length) throws IOException {
FileChannel read = new RandomAccessFile(f, "r").getChannel();
File tmp = File.createTempFile("ChangeMetaData", "splitFileAndInsert");
FileChannel tmpWrite = new RandomAccessFile(tmp, "rw").getChannel();
read.position(pos);
tmpWrite.transferFrom(read, 0, read.size() - pos);
read.close();
FileChannel write = new RandomAccessFile(f, "rw").getChannel();
write.position(pos + length);
tmpWrite.position(0);
long transferred = 0;
while ((transferred += tmpWrite.transferTo(0, tmpWrite.size() - transferred, write)) != tmpWrite.size()) {
System.out.println(transferred);
}
System.out.println(transferred);
tmpWrite.close();
tmp.delete();
return write;
}
private boolean needsOffsetCorrection(IsoFile isoFile) {
if (Path.getPath(isoFile, "moov[0]/mvex[0]") != null) {
// Fragmented files don't need a correction
return false;
} else {
// no correction needed if mdat is before moov as insert into moov want change the offsets of mdat
for (Box box : isoFile.getBoxes()) {
if ("moov".equals(box.getType())) {
return true;
}
if ("mdat".equals(box.getType())) {
return false;
}
}
throw new RuntimeException("I need moov or mdat. Otherwise all this doesn't make sense");
}
}
public void writeMetadata(String videoFilePath, String theTitle, String theDate) throws IOException {
File videoFile = new File(videoFilePath);
if (!videoFile.exists()) {
throw new FileNotFoundException("File " + videoFilePath + " not exists");
}
if (!videoFile.canWrite()) {
throw new IllegalStateException("No write permissions to file " + videoFilePath);
}
IsoFile isoFile = new IsoFile(videoFilePath);
MovieBox moov = isoFile.getBoxes(MovieBox.class).get(0);
FreeBox freeBox = findFreeBox(moov);
boolean correctOffset = needsOffsetCorrection(isoFile);
long sizeBefore = moov.getSize();
long offset = 0;
for (Box box : isoFile.getBoxes()) {
if ("moov".equals(box.getType())) {
break;
}
offset += box.getSize();
}
// Create structure or just navigate to Apple List Box.
UserDataBox userDataBox;
if ((userDataBox = Path.getPath(moov, "udta")) == null) {
userDataBox = new UserDataBox();
moov.addBox(userDataBox);
}
MetaBox metaBox;
if ((metaBox = Path.getPath(userDataBox, "meta")) == null) {
metaBox = new MetaBox();
HandlerBox hdlr;
hdlr = new HandlerBox();
hdlr.setHandlerType("mdir");
metaBox.addBox(hdlr);
userDataBox.addBox(metaBox);
}
AppleItemListBox ilst;
if ((ilst = Path.getPath(metaBox, "ilst")) == null) {
ilst = new AppleItemListBox();
metaBox.addBox(ilst);
}
if (freeBox == null) {
freeBox = new FreeBox(128 * 1024);
metaBox.addBox(freeBox);
}
// Got Apple List Box
AppleNameBox nam;
if ((nam = Path.getPath(ilst, AppleNameBox.TYPE)) == null) {
nam = new AppleNameBox();
}
nam.setDataCountry(0);
nam.setDataLanguage(0);
nam.setValue(theTitle);
ilst.addBox(nam);
AppleRecordingYear2Box day;
if ((day = Path.getPath(ilst, "©day")) == null) {
day = new AppleRecordingYear2Box();
}
day.setDataCountry(0);
day.setDataLanguage(0);
day.setValue(theDate);
ilst.addBox(day);
long sizeAfter = moov.getSize();
long diff = sizeAfter - sizeBefore;
// This is the difference of before/after
// can we compensate by resizing a Free Box we have found?
if (freeBox.getData().limit() > diff) {
// either shrink or grow!
freeBox.setData(ByteBuffer.allocate((int) (freeBox.getData().limit() - diff)));
sizeAfter = moov.getSize();
diff = sizeAfter - sizeBefore;
}
if (correctOffset && diff != 0) {
correctChunkOffsets(moov, diff);
}
BetterByteArrayOutputStream baos = new BetterByteArrayOutputStream();
moov.getBox(Channels.newChannel(baos));
isoFile.close();
FileChannel fc;
if (diff != 0) {
// this is not good: We have to insert bytes in the middle of the file
// and this costs time as it requires re-writing most of the file's data
fc = splitFileAndInsert(videoFile, offset, sizeAfter - sizeBefore);
} else {
// simple overwrite of something with the file
fc = new RandomAccessFile(videoFile, "rw").getChannel();
}
fc.position(offset);
fc.write(ByteBuffer.wrap(baos.getBuffer(), 0, baos.size()));
fc.close();
}
FreeBox findFreeBox(Container c) {
for (Box box : c.getBoxes()) {
System.err.println(box.getType());
if (box instanceof FreeBox) {
return (FreeBox) box;
}
if (box instanceof Container) {
FreeBox freeBox = findFreeBox((Container) box);
if (freeBox != null) {
return freeBox;
}
}
}
return null;
}
private void correctChunkOffsets(MovieBox movieBox, long correction) {
List<ChunkOffsetBox> chunkOffsetBoxes = Path.getPaths((Box) movieBox, "trak/mdia[0]/minf[0]/stbl[0]/stco[0]");
if (chunkOffsetBoxes.isEmpty()) {
chunkOffsetBoxes = Path.getPaths((Box) movieBox, "trak/mdia[0]/minf[0]/stbl[0]/st64[0]");
}
for (ChunkOffsetBox chunkOffsetBox : chunkOffsetBoxes) {
long[] cOffsets = chunkOffsetBox.getChunkOffsets();
for (int i = 0; i < cOffsets.length; i++) {
cOffsets[i] += correction;
}
}
}
private static class BetterByteArrayOutputStream extends ByteArrayOutputStream {
byte[] getBuffer() {
return buf;
}
}
}
使用法:
new Mp4MetadataWriter().writeMetadata("/home/user/downloads/1.mp4", "Yet another video title", "2020");
+0
Nikolai Doronin、お返事ありがとうございます。あなたのソリューションはほとんどのビデオで正常に動作しますが、私の場合はそうではありません。私は 'MediaCodec'の助けを借りてビデオをエンコードし、' MediaMuxer'でパックします。結果ビデオの例は、https://dl.dropboxusercontent.com/u/15506779/persistent/edufii/issues/mp4parser-151.mp4を参照してください。このビデオのmp4parser 1.1.18はOOMをスローします。詳細はこちらhttps://github.com/sannies/mp4parser/issues/151 – danik
関連する問題
- 1. Pythonのmp4メタデータ抽出
- 2. OSMFのFlashビデオmp4メタデータ
- 3. メタデータをiTextSharpで設定する
- 4. ExtJS DirectStoreのフィールドのメタデータ設定
- 5. Android:読み込みと書き込み.mp4メタデータ - タグ
- 6. 大きなファイル(ビデオ/ mp4)をアップロードする設定ですか?
- 7. s3のmp4ファイルのコンテンツタイプを設定する
- 8. haskellでffmpeg-lightを使ってmp4メタデータを見つける方法は?
- 9. オーディオファイルのID3タグ(メタデータ)を取得(設定)する方法は?
- 10. サービススタック認証の拡張 - カスタムユーザー認証メタデータによるユーザーセッションの設定
- 11. MediaWiki APIを使用してカテゴリとその他のメタデータを設定する
- 12. resque-statusハッシュのメタデータを設定することができません
- 13. 他のメタデータから継承するメタデータを設定すると同時に、ユーザーデータを別のタイプに変更する方法を教えてください。
- 14. メタデータ
- 15. メタデータ
- 16. s3cmdを使用してメタデータを設定して、静的なWebサイトをAmazon S3にアップロード
- 17. MP4ファイルのGLvideoFrame
- 18. html5 mp4ビデオプレーヤー
- 19. MP4ビデオ - ここ
- 20. ios html5 video mp4
- 21. Mencoder Mp4(x264)エンコーディング
- 22. MediaSource APIとmp4
- 23. pac4j-samlを使用すると、shiro.iniの設定に基づいてspメタデータを取得する方法
- 24. テーブルにメタデータを収集
- 25. mkvビデオストリームをmp4に即時にリビジョンアップ
- 26. 断片化されたMP4を複数のMP4ファイルに分割する
- 27. (マルチサーバークラスタの設定)を設定Umbraco distributedCallを適切に設定
- 28. aws s3apiでメタデータを設定するにはどうすればよいですか?
- 29. UIImageメタデータ
- 30. プライベートモード - メタデータ
何を記載してくださいあなたがしようとした。 – Reinard
@Reinard私は私の質問を編集しました。 – danik