ロッシーまたはロスレス?


18

音声ファイルを指定して、それが非可逆形式でエンコードされているか、可逆形式でエンコードされているかを判断します。この課題のために、分類する必要があるのは次の形式のみです。

ルール

  • 入力がファイル名の形式で行われる場合、ファイル名について何も仮定する必要はありません(たとえば、拡張子が形式に対して正しいこと、または存在することさえ保証されません)。
  • 入力ファイルにはID3またはAPEv2メタデータは存在しません。
  • 0and 1lossyand losslessfooand barなどなど、2つの一意で区別可能な出力を使用できます。

テストケース

この挑戦のためのテストケースがあり、zipファイルで構成され、ここで二つのディレクトリが含まれていますlossylossless。各ディレクトリには、さまざまな形式でエンコードされたすべて0.5秒の440 Hz正弦波である複数のオーディオファイルが含まれています。すべてのオーディオファイルには、A440.m4a(MPEGレイヤー4コンテナのAACオーディオである)例外を除いて、上記の形式に一致する拡張子があります。


MPEGレイヤー4コンテナ内のAACオーディオ」は疑問を提起します。答えは、他のどのコンテナ形式で処理する必要がありますか?
ピーターテイラー

@PeterTaylor AACのみに特別な言及がありました。FFMPEGを介してMPEGレイヤー4コンテナーに埋め込むことなくAACオーディオを提供する方法を見つけることができなかったからです。VorbisオーディオはOggコンテナに埋め込まれています(Vorbisオーディオの標準と同様)。他のすべてはスタンドアロン形式です。
Mego

TTAファイルについて確かですか?仕様によると、TTAファイルはマジックナンバーTTA1またはTTA2で始まる必要があります。FFM2(ファイルのマジック番号)はFFmpegストリームに対応しているようです。Linux ファイルはTTA1ヘッダーを認識しますが、FFM2ヘッダーは認識しません。
デニス

また、AACは常にMPEGレイヤー4ヘッダーにあると想定できますか?そうでない場合、何を想定できますか?
デニス

ファイルの内容を入力として取得できますか、またはコードで取得する必要がありますか?
シャギー

回答:


18

ゼリー7 5バイト

ƈƈeØA

非可逆形式は0を返し、非可逆形式は1を返します。

オンラインでお試しください!(要旨のパーマリンク)

バックグラウンド

サポートしなければならないフォーマットには、次のマジックナンバーがあります。つまり、これらのバイトで始まります。

Format    Header (text)       Header (hex)
-----------------------------------------------------------------------------------
AC3       .w                  0B 77
AMR       #!AMR               23 21 41 4D 52
AAC       ÿñP@..ü             FF F1 50 40 00 1F FC
  M4A     ... ftypM4A         00 00 00 20 66 74 79 70 4D 34 41 20
MP2       ÿû                  FF FB
MP3       ÿû                  FF FB
OGG       OggS                4F 67 67 53
WMA       0&²u.fÏ.¦Ù.ª.bÎl    30 26 B2 75 8E 66 CF 11 A6 D9 00 AA 00 62 CE 6C

AIFF      FORM????AIFF        46 4F 52 4D ?? ?? ?? ?? 41 49 46 46
FLAC      fLaC                66 4C 61 43
TTA       TTA1                54 54 41 31
  FFM2    FFM2                46 46 4D 32
WAV       RIFF????WAVE        52 49 46 46 ?? ?? ?? ?? 57 41 56 45

インデントされたエントリは、テストケースに表示される前述の形式のコンテナです。?は可変バイトを示します。.印刷できないバイトを示します。他のすべてのバイトは、ISO 8859-1文字として表示されます。

2番目のバイトだけを見ると、簡単な方法で形式を決定できます。

ロスレス形式には2番目のバイトとして大文字がありますが、ロッシー形式にはありません。

使い方

ƈƈeØA  Main link. No arguments.

ƈ      Read a char from STDIN and set the left argument to this character.
 ƈ     Read another char from STDIN and set the return value to this character.
   ØA  Yield the uppercase alphabet, i.e., "ABCDEFGHIJKLMNOPQRSTUVWXYZ".
  e    Exists; return 1 if the return value (second char on STDIN) belongs to the
       uppercase alphabet, 0 if not.

2
これは非常に賢い解決策です。
メゴ

10

C、82 80 32バイト

@Dennisの答えに触発され、これはさらに減らすことができます。

main(){return getchar()&200^64;}

ファイルデータをstdinにパイプします。ロスレスの場合は0、非可逆の場合はゼロ以外を返します。

または、元の長いチェック:

char v[5];main(){scanf("%4c",v);return*v&&strstr("fLaC FORM RIFF TTA1 FFM2",v);}

ファイルデータをstdinにパイプします。ロスレスの場合はゼロ以外(1)を、ロスのある場合は0を返します。

私が言うことができることから、あなたがリストしたすべてのフォーマットは別々のマジックナンバーを持っています(AIFF / WAVを除き、両方ともとにかくロスレスです)ので、これは既知のロスレス値のマジックナンバーをチェックするだけです。これ*v&&は、ヌルバイト(M4A)で始まる一致するファイルから保護するためです。

スペックシートで見つけた値(fLaC= FLAC、RIFF= WAV / AIFF、TTA1= TTA)を含めました。FORM= AIFFおよびFFM2= TTAは提供されたサンプルファイルからのものです(これらはラッパー形式またはそれ以降のバージョンであると推測できます)。


または、より短い感じのごまかしの代替:

Bash +ファイル、61バイト

N="$(file "$1")";[[ $N = *": d"* || $N = *IF* || $N = *FL* ]]

引数としてファイル名を取ります。ロスレスの場合は0、非可逆の場合はゼロ以外を返します。

期待どおりに動作します。fileファイルタイプが何であるかを尋ね、既知のパターンをチェックします。TTA一致: d: data)、AIFF / WAV一致IF、およびFLAC一致FL。ロスレスの結果はこれらのいずれにも一致しません。ファイル名が削除されても引き続き機能することをテストしました。


テスト:

for f in "$@"; do
    echo "Checking $f:";
    ./identify2 "$f" && echo "shorter C says LOSSLESS" || echo "shorter C says LOSSY";
    ./identify < "$f" && echo "longer C says LOSSY" || echo "longer C says LOSSLESS";
    ./identify.sh "$f" && echo "file says LOSSLESS" || echo "file says LOSSY";
done;

# This can be invoked to test all files at once with:
./identify_all.sh */*

ファイル拡張子が正しくない場合、Bashソリューションも機能しますか?「拡張子は形式に対して正しいことが保証されていない」ため、ファイルに間違った拡張子を付けても機能するはずです。
mbomb007

@ mbomb007私はちょうど拡張機能を混ぜてテストしましたが、それでもそれらをうまく識別します。fileとにかく拡張機能を信頼していないと思います(多くのユーザーはpngをjpegにリネームすることはそれを変換するのと同じです!)
Dave

7

GS2、3バイト

◄5ì

非可逆形式は0を返し、非可逆形式は1を返します。

オンラインでお試しください!(要旨のパーマリンク)

バックグラウンド

サポートしなければならないフォーマットには、次のマジックナンバーがあります。つまり、これらのバイトで始まります。

Format    Header (text)       Header (hex)
-----------------------------------------------------------------------------------
AC3       .w                  0B 77
AMR       #!AMR               23 21 41 4D 52
AAC       ÿñP@..ü             FF F1 50 40 00 1F FC
  M4A     ... ftypM4A         00 00 00 20 66 74 79 70 4D 34 41 20
MP2       ÿû                  FF FB
MP3       ÿû                  FF FB
OGG       OggS                4F 67 67 53
WMA       0&²u.fÏ.¦Ù.ª.bÎl    30 26 B2 75 8E 66 CF 11 A6 D9 00 AA 00 62 CE 6C

AIFF      FORM????AIFF        46 4F 52 4D ?? ?? ?? ?? 41 49 46 46
FLAC      fLaC                66 4C 61 43
TTA       TTA1                54 54 41 31
  FFM2    FFM2                46 46 4D 32
WAV       RIFF????WAVE        52 49 46 46 ?? ?? ?? ?? 57 41 56 45

インデントされたエントリは、テストケースに表示される前述の形式のコンテナです。?は可変バイトを示します。.印刷できないバイトを示します。他のすべてのバイトは、ISO 8859-1文字として表示されます。

2番目のバイトだけを見ると、簡単な方法で形式を決定できます。

ロスレス形式には2番目のバイトとして大文字がありますが、ロッシー形式にはありません。

使い方

     (implcit) Push the entire input from STDIN as a string on the stack.
◄    Push 1.
 5   Get the strings character at index 1, i.e., its second character.
  ì  Test if the character is an uppercase letter.

2

JavaScript(ES6)、20バイト

c=>/^[fFRT]/.test(c)

説明

入力戻るようにファイルの内容を取得しtrue、ファイルが可逆である場合、またはfalseそれがあるかどうかを確認するために、入力の最初の文字をテストすることにより、非可逆である場合にfFRまたはT


それを試してみてください

ファイルの内容をに貼り付けますtextarea

f=
c=>/^[fFRT]/.test(c)
i.addEventListener("input",_=>console.log(f(i.value)))
<textarea id=i></textarea>


第二の努力、81 63バイト

指定されたURLからファイルのコンテンツをフェッチしますが、これは過剰であることが判明しました。

u=>fetch(u).then(r=>r.text()).then(t=>alert(/^[fFRT]/.test(t)))

最初の努力、146 116 89バイト

MIMEタイプは拡張機能に関連付けられているため無効であり、明らかに、応答ヘッダーは追加の入力として適格です。

u=>fetch(u).then(r=>alert(/aiff|flac|tta|wave|wav$/.test(r.headers.get("Content-Type"))))

Webサーバーは通常、ファイル拡張子に基づいてMIMEを生成しますが、これはここでの規則に違反しています。拡張子なしで提供されるファイルで機能するかどうかを確認しましたか?(その場合、おそらく「言語」の一部として使用しているサーバーの名前を含める必要があります)
デイブ

1
@Dave彼らはそうではないと確信しています。MIMEと拡張子は互いにまったく依存していません。ファイルの拡張子を変更してアップロードする場合、MIMEタイプは拡張子ではなく、ファイルの実際のコンテンツのMIMEです。ただし、入力をURLとして取得することはおそらく許可されません。よく分かりません。
mbomb007

@ mbomb007なぜあなたはそれを言うのかわかりません。MIMEタイプはファイルシステム/ファイルではなくインターネットのものであり、私が知っているサーバーは設定されたルックアップを使用して拡張子に基づいてそれを決定します(ヘッダーを提供する速度のため、提供する前にすべてのファイルを検査したくないそれ)。たとえば、ApacheのAddType <mime> <extension>、またはIISを見てください<MimeMap>。もちろん、特定のセットアップまたはファイルホスティングツールで適切な検査を行うことができ、サーバーの選択を回答の一部にする価値があります(ファイルタイプを決定しているのはサーバーだからです!)
Dave

1
.NETでファイルの検証を行ったところ、アップロード前に拡張子が変更された場合でも、MIMEタイプはコンテンツと一致しました。
mbomb007

@ mbomb007その後、使用した.NETコンポーネントのいずれかが、アップロード中またはファイルの提供中にファイル検査を実行している必要があります(パフォーマンスのためにアップロード中に推測しますが、わかりません)。元のコメントに戻ると、この答えは「JavaScript + .NET SeverLibraryXYZ」のようになります。URLからの入力については、なぜあなたがためらっているのかはわかりますが、個人的にはサーバーの選択が言及されている限り、それが有効であると考えています。既存のメタがあるかもしれませんが、最終的にはもちろんMegoに任されています。
デイブ

1

チップ、11バイト

~Z~S
t'G~aF

デニスのジェリーの答えをチップで恥知らずに複製しました。

ロスレスリターン0x0、ロッシーリターン0x1

オンライン試してみてください、リンクは要点です(TIO戦略についてはDennisに感謝します)

説明して!

~Z~S
t'

この部分はハウスキーピングです。S最初のバイトをtスキップし、2番目のバイトの後に消去します。

G~aF

これが決定の要です。各入力バイトはビットによってアクセスされますHGFEDCBA。場合Gセットであり、Fバイトが範囲内であることを意味することではない0x400x5f(「大文字」、及び手元のタスクのために十分に良いとほぼ同等です)。

ただし、バイトを節約G and (not F)するために(not G) or F、この決定をからに反転します。チップではorが暗黙的になる可能性があるためです。

この結果の真/偽の値はa、出力の最下位ビットであるに配置されます。(他のすべてのビットはゼロになります)。TIOでは、値が見えるようにhexdumpを介して出力を実行します。

同様に、C風の場合、次のようになります。

out_byte = !(in_byte & 0x40) && (in_byte & 0x20)

1

Cubix、16バイト

$-!u'HIa'@/1@O<

ネット形式:

    $ -
    ! u
' H I a ' @ / 1
@ O < . . . . .
    . .
    . .

自分で試してみてください

ファイルの10進バイト値は、個別のリストに入力する必要があります。区切り文字は関係なく、数字でもマイナス記号でもないもので十分です。コードは実際には最初のバイトのみを対象としているため、必要に応じてファイルの残りを省くことができます。このプログラムは0、ロスレス、および1ロッシー用に出力します。ここで試してみてください!デフォルトの入力ではFLACヘッダーが使用されます。

説明

ファイルの良いところは、(ほぼ)それらのすべてがいわゆるマジックを持っていることです。これらは、ファイルの最初の数バイトです。優れたソフトウェアは、ファイル拡張子をチェックするのではなく、特定のファイルを処理できるかどうかを確認するためのファイルマジックをチェックします。

デニスはこのマジックを使用して圧縮タイプを見つける方法を見つけましたが、彼が最初のバイトを破棄したという事実から、2番目ではなく1番目のバイトを使用するメソッドを考え出しました。結局のところ、このコミュニティはすべてバイトの節約に関するものです。

さまざまなファイルタイプの最初のバイトのリストを以下に示します。私はそれらを2つのグループに分けました:不可逆的と可逆的です。10進数、16進数、および2進数の最初のバイトの値を以下に示します。すでにパターンが表示されている場合があります...

Lossy:                  Lossless:
255:0xFF:0b11111111     102:0x66:0b01100110
 79:0x4F:0b01001111      84:0x54:0b01010100
 35:0x23:0b00100011      82:0x52:0b01010010
 11:0x0B:0b00001011      70:0x46:0b01000110
  0:0x00:0b00000000

私が見たパターンは、2番目のビット(左から右に数える)が「ロスレス」バイトで常にオンであり、5番目のビットが常にオフであったということでした。この組み合わせは、損失の多い形式では表示されません。これを「抽出」するには、単にバイナリAND(by 0b01001000 (=72))を実行してからと比較し0b01000000 (=64)ます。両方が等しい場合、入力形式は可逆であり、そうでない場合は不可逆です。

残念ながら、Cubixにはそのような比較演算子がないため、減算を使用しました(結果が64の場合、これは0になり、それ以外の場合は8、-56または-64になります。これについては後で説明します。

まず、プログラムの最初から始めましょう。バイナリANDは、a次のコマンドを使用して実行されます。

'HIa
'H   # Push 0b01001000 (72)
  I  # Push input
   a # Push input&72

次に、減算を使用して64と比較します(この部分の中央のIP [1行目、2番目の文字、南を指す]にIPを反映するミラーにヒットします)。

'@-
'@  # Push 0b01000000 (64)
  - # Subtract from (input&72)
    # Yields 0 for lossy, non-zero otherwise

によってIPが方向転換された後、スタックの最上部がゼロ以外の場合(およびその場合のみ)、u制御フローを使用してa 1をスタックにプッシュします。

!$1
!   # if top = 0:
 $1 #   do nothing
    # else:
  1 #   push 1

キューブをラップした後、<命令をヒットします。これにより、4番目の行でIPが西に向けられます。あとは、出力して終了するだけです。

O@
O  # Output top of the stack as number
 @ # End program

そのため、プログラム0はロスレスおよびロスのある出力を出力し1ます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.