Mất mát hay mất mát?


18

Đưa ra một tệp âm thanh, xác định xem nó được mã hóa ở định dạng lossy hay lossless. Đối với mục đích của thách thức này, chỉ cần phân loại các định dạng sau:

Quy tắc

  • Nếu đầu vào được thực hiện dưới dạng tên tệp, không nên đưa ra giả định nào về tên tệp (ví dụ: phần mở rộng không được đảm bảo là chính xác cho định dạng hoặc thậm chí là hiện tại).
  • Sẽ không có siêu dữ liệu ID3 hoặc APEv2 trong các tệp đầu vào.
  • Bất kỳ hai kết quả đầu ra độc đáo và phân biệt có thể được sử dụng, chẳng hạn như 01, lossylossless, foobarvv

Các trường hợp thử nghiệm

Các trường hợp thử nghiệm cho thử thách này bao gồm một tệp zip nằm ở đây có chứa hai thư mục: lossylossless. Mỗi thư mục chứa một số tệp âm thanh là tất cả các sóng hình sin 440 Hz 0,5 giây, được mã hóa ở các định dạng khác nhau. Tất cả các tệp âm thanh đều có phần mở rộng khớp với các định dạng ở trên, ngoại trừ A440.m4a(đó là âm thanh AAC trong bộ chứa MPEG Layer 4).


" Âm thanh AAC trong bộ chứa MPEG Lớp 4 " đặt ra câu hỏi: câu trả lời nào cần các định dạng chứa khác để xử lý?
Peter Taylor

@PeterTaylor Chỉ AAC được đề cập đặc biệt vì tôi không thể tìm cách cung cấp âm thanh AAC mà không nhúng nó vào bộ chứa MPEG Layer 4 thông qua FFMPEG. Âm thanh Vorbis được nhúng trong thùng chứa Ogg (như là tiêu chuẩn cho âm thanh Vorbis). Tất cả những người khác là định dạng độc lập.
Mego

Bạn có chắc chắn về tập tin TTA? Theo thông số kỹ thuật , các tệp TTA nên bắt đầu bằng số ma thuật TTA1 hoặc TTA2. FFM2 (số ma thuật của tệp của bạn) xuất hiện tương ứng với luồng FFmpeg. Tệp Linux nhận ra tiêu đề TTA1, nhưng không phải là tiêu đề FFM2.
Dennis

Ngoài ra, chúng ta có thể giả sử rằng AAC sẽ luôn ở trong tiêu đề MPEG Lớp 4 không? Nếu không, chúng ta có thể giả định điều gì?
Dennis

Chúng tôi có thể lấy nội dung của tệp làm đầu vào không hoặc mã của chúng tôi có phải truy xuất chúng không?
Xù xì

Câu trả lời:


18

Thạch , 7 5 byte

ƈƈeØA

Các định dạng lossy trả về 0 , các định dạng lossless trả về 1 .

Hãy thử trực tuyến!(permalinks trong Gist)

Lý lịch

Các định dạng chúng tôi phải hỗ trợ có các số ma thuật sau, nghĩa là chúng bắt đầu bằng các byte này.

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

Các mục được thụt lề là các thùng chứa cho định dạng trước xuất hiện trong các trường hợp thử nghiệm. ?biểu thị một byte biến..biểu thị một byte không thể in được. Tất cả các byte khác được hiển thị dưới dạng ký tự ISO 8859-1 của chúng.

Bằng cách chỉ nhìn vào byte thứ hai, chúng ta có thể xác định định dạng một cách dễ dàng:

Các định dạng lossless có một chữ cái viết hoa là byte thứ hai của chúng, trong khi các định dạng lossy thì không.

Làm thế nào nó hoạt động

ƈƈ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
Đây là một giải pháp rất thông minh.
Mego

10

C, 82 80 32 byte

Lấy cảm hứng từ câu trả lời của @Dennis , điều này có thể được giảm hơn nữa:

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

Ống dữ liệu tập tin để stdin. Trả về 0 cho lossless, hoặc nonzero cho lossy.

Hoặc kiểm tra bản gốc dài hơn:

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

Ống dữ liệu tập tin để stdin. Trả về giá trị khác (1) cho lossless hoặc 0 cho lossy.

Từ những gì tôi có thể nói, tất cả các định dạng bạn liệt kê đều có các số ma thuật riêng biệt (ngoại trừ AIFF / WAV, nhưng cả hai đều không mất dữ liệu), do đó, điều này chỉ kiểm tra số ma thuật đó cho giá trị tổn thất đã biết. Đây *v&&chỉ là để bảo vệ chống lại các tệp phù hợp bắt đầu bằng byte rỗng (M4A).

Tôi đã bao gồm các giá trị tôi tìm thấy trong các tờ đặc tả ( fLaC= FLAC, RIFF= WAV / AIFF, TTA1= TTA) và FORM= AIFF và FFM2= TTA là từ các tệp mẫu được cung cấp (tôi chỉ có thể đoán đây là các định dạng trình bao hoặc các phiên bản mới hơn).


Hoặc một sự thay thế ngắn hơn giống như gian lận:

Tệp Bash +, 61 byte

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

Lấy tên tệp làm đối số. Trả về 0 cho lossless, hoặc nonzero cho lossy.

Có chính xác những gì bạn mong đợi; hỏi filefiletype là gì, sau đó kiểm tra các mẫu đã biết. Các trận đấu TTA : d( : data), trận đấu AIFF / WAV IFvà trận đấu FLAC FL. Không có kết quả lossless nào phù hợp với bất kỳ kết quả nào trong số này và tôi đã kiểm tra rằng nó vẫn hoạt động nếu tên tệp bị xóa.


Kiểm tra:

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 */*

Giải pháp Bash của bạn cũng hoạt động nếu phần mở rộng tệp không chính xác? "tiện ích mở rộng không được đảm bảo là chính xác cho định dạng", vì vậy bạn có thể cung cấp cho một tệp tiện ích mở rộng sai và vẫn hoạt động.
mbomb007

@ mbomb007 Tôi vừa thử nghiệm với các tiện ích mở rộng lẫn lộn và nó vẫn xác định chúng ổn. Tôi nghĩ filedù sao cũng không tin tưởng các tiện ích mở rộng (rất nhiều người dùng đổi tên png thành jpeg cũng giống như chuyển đổi nó!)
Dave

7

GS2 , 3 byte

◄5ì

Các định dạng lossy trả về 0 , các định dạng lossless trả về 1 .

Hãy thử trực tuyến! (permalinks trong Gist)

Lý lịch

Các định dạng chúng tôi phải hỗ trợ có các số ma thuật sau, nghĩa là chúng bắt đầu bằng các byte này.

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

Các mục được thụt lề là các thùng chứa cho định dạng trước xuất hiện trong các trường hợp thử nghiệm. ?biểu thị một byte biến. .biểu thị một byte không thể in được. Tất cả các byte khác được hiển thị dưới dạng ký tự ISO 8859-1 của chúng.

Bằng cách chỉ nhìn vào byte thứ hai, chúng ta có thể xác định định dạng một cách dễ dàng:

Các định dạng lossless có một chữ cái viết hoa là byte thứ hai của chúng, trong khi các định dạng lossy thì không.

Làm thế nào nó hoạt động

     (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 byte

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

Giải trình

Đưa các nội dung của tập tin như một đầu vào và trả về truenếu file là lossless hoặc falsenếu nó là tổn hao bằng cách kiểm tra các ký tự đầu tiên của đầu vào đó để xem nếu nó là một f, F, Rhoặc T.


Thử nó

Dán nội dung của một tập tin vào textarea.

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


Nỗ lực thứ hai, 81 63 byte

Lấy nội dung của tệp từ một URL được cung cấp, hóa ra là quá mức cần thiết.

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

Nỗ lực đầu tiên, 146 116 89 byte

Không hợp lệ vì các loại mime được gắn với các tiện ích mở rộng và rõ ràng, các tiêu đề phản hồi đủ điều kiện là đầu vào bổ sung.

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

máy chủ web thường tạo MIME dựa trên phần mở rộng tệp, trái với quy tắc ở đây. Bạn đã kiểm tra nếu nó hoạt động trên các tập tin được phục vụ mà không có phần mở rộng? (nếu có thì có lẽ bạn nên bao gồm tên của máy chủ bạn đang sử dụng như một phần của "ngôn ngữ")
Dave

1
@Dave Khá chắc chắn họ không. MIME và phần mở rộng hoàn toàn không phụ thuộc vào nhau. Nếu bạn thay đổi phần mở rộng của tệp và tải lên, loại MIME là MIME của nội dung thực tế của tệp, không phải phần mở rộng. Mặc dù vậy, việc lấy đầu vào làm URL có thể không được phép. Tôi không chắc.
mbomb007

@ mbomb007 Tôi không chắc tại sao bạn nói vậy; các loại mime là một thứ trên internet, không phải là hệ thống tệp / tệp và các máy chủ mà tôi biết sẽ xác định nó dựa trên tiện ích mở rộng bằng cách tra cứu được định cấu hình (để biết tốc độ phục vụ của tiêu đề; họ không muốn kiểm tra mọi tệp trước khi phục vụ nó). Lấy ví dụ như của Apache AddType <mime> <extension>hoặc IIS <MimeMap>. Tất nhiên, một công cụ thiết lập hoặc lưu trữ tệp cụ thể có thể thực hiện kiểm tra thích hợp và điều đó sẽ giúp cho sự lựa chọn máy chủ trở thành một phần của câu trả lời (vì đó là máy chủ xác định kiểu tệp!)
Dave

1
Tôi đã thực hiện xác thực tệp bằng .NET và loại MIME khớp với nội dung ngay cả khi tiện ích mở rộng được thay đổi trước khi tải lên.
mbomb007

@ mbomb007 thì bất kỳ thành phần .NET nào bạn đã sử dụng đều phải thực hiện kiểm tra tệp trong khi tải lên hoặc khi phục vụ các tệp (Tôi đoán trong quá trình tải lên để thực hiện, nhưng bạn không bao giờ biết). Vì vậy, quay trở lại nhận xét ban đầu của tôi, điều đó sẽ khiến câu trả lời này giống như "JavaScript + .NET SeverL LibraryXYZ". Đối với việc lấy đầu vào từ một URL, tôi có thể thấy lý do tại sao bạn do dự nhưng cá nhân tôi cho rằng nó hợp lệ miễn là lựa chọn máy chủ được đề cập. Có thể có một meta hiện có trên đó, nhưng cuối cùng tất nhiên là tùy thuộc vào Mego.
Dave

1

Chip , 11 byte

~Z~S
t'G~aF

Không biết sao chép câu trả lời của Dennis 'Jelly trong Chip.

Lợi nhuận thua lỗ 0x0, lợi nhuận thua lỗ 0x1.

Dùng thử trực tuyến , liên kết trong ý chính (cảm ơn Dennis cho chiến lược TIO tại đây)

Giải thích!

~Z~S
t'

Phần này là dịch vụ dọn phòng: nó Slấy byte đầu tiên và txuất hiện sau byte thứ hai.

G~aF

Đây là thịt của quyết định. Mỗi byte đầu vào được truy cập bởi các bit HGFEDCBA. Nếu Glà thiết lập, và Fkhông phải là, có nghĩa là các byte nằm trong phạm vi 0x40cho0x5f (đó là tương đương với 'hoa', và đủ tốt cho các nhiệm vụ trong tầm tay).

Tuy nhiên, để tiết kiệm byte, tôi nghịch quyết định này từ G and (not F)đến(not G) or F , vì hay có thể là tiềm ẩn trong Chip.

Giá trị đúng / sai kết quả này sau đó được đặt vào a, đây là bit thấp nhất của đầu ra. (Tất cả các bit khác sẽ bằng không). Trong TIO, tôi chạy đầu ra thông qua hexdump để hiển thị các giá trị.

Tương tự, trong C-ish, người ta sẽ nói một cái gì đó như:

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

1

Hình khối, 16 byte

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

Hình thức mạng:

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

Tự mình thử

Bạn nên nhập các giá trị byte thập phân của tệp trong một danh sách riêng biệt. Dấu phân cách không quan trọng, bất cứ điều gì không phải là một chữ số hoặc dấu trừ đều đủ. Mã thực sự chỉ quan tâm đến byte đầu tiên, vì vậy bạn có thể bỏ phần còn lại của tệp nếu muốn. Các chương trình đầu ra 0cho lossless, và 1cho lossy. Hãy thử nó ở đây ! Đầu vào mặc định sử dụng tiêu đề FLAC.

Giải trình

Điều hay ho về các tập tin là (gần như) tất cả chúng đều có một thứ gọi là ma thuật. Đó là một vài byte đầu tiên của tập tin. Phần mềm tốt không kiểm tra phần mở rộng tệp, mà là ma thuật tệp để xem liệu nó có thể xử lý một tệp nhất định không.

Dennis đã tìm ra cách sử dụng phép thuật này để tìm loại nén, nhưng thực tế là anh ấy đã loại bỏ byte đầu tiên khiến tôi muốn thử đưa ra một phương thức sử dụng byte đầu tiên, thay vì thứ hai. Rốt cuộc, cộng đồng này là tất cả về việc lưu byte.

Đây là danh sách các byte đầu tiên của các loại tệp khác nhau. Tôi ra lệnh cho họ thành hai nhóm: mất mát và mất mát. Dưới đây là các giá trị của byte đầu tiên của chúng ở dạng thập phân, thập lục phân và nhị phân. Bạn có thể thấy một mô hình đã ...

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

Mẫu mà tôi thấy, là bit thứ hai (được tính từ trái sang phải) luôn bật trên các byte "lossless" và bit thứ năm luôn bị tắt. Sự kết hợp này không xuất hiện trong bất kỳ định dạng mất mát nào. Để "giải nén" điều này, chúng ta chỉ cần thực hiện một nhị phân AND (bằng 0b01001000 (=72)) và sau đó so sánh với 0b01000000 (=64). Nếu cả hai đều bằng nhau, định dạng đầu vào là lossless, nếu không thì mất.

Đáng buồn thay, Cubix không có toán tử so sánh như vậy, vì vậy tôi đã sử dụng phép trừ (nếu kết quả là 64, kết quả này là 0 và kết quả là 8, -56 hoặc -64 nếu không tôi sẽ quay lại vấn đề này sau.

Đầu tiên, hãy bắt đầu từ đầu chương trình. AND nhị phân được thực hiện bằng alệnh:

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

Sau đó, chúng tôi so sánh với 64 bằng cách sử dụng phép trừ (lưu ý chúng tôi nhấn một gương phản chiếu IP lên mặt trên [dòng đầu tiên, ký tự thứ hai, chỉ về phía nam] ở giữa phần này).

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

Sau khi IP được quay xung quanh u, chúng tôi sử dụng một số luồng điều khiển để đẩy a 1đến ngăn xếp nếu (và chỉ khi) đỉnh của ngăn xếp khác không:

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

Sau khi chúng tôi quấn quanh khối lập phương, chúng tôi nhấn vào <hướng dẫn, điểm IP phía tây trên dòng thứ tư. Tất cả những gì còn lại phải làm là đầu ra và chấm dứt.

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

Vì vậy, chương trình đầu ra 0cho lossless, và 1cho lossy.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.