Mark MP3 as copy determent - php

As a copy determent for my mp3-files (handed out individually or over web shop) I thought about marking the files each by cart-code-token, which I have to keep for legal reasons anyways.
Contra:
With basic understanding of the mp3 codec I came up with the idea of putting the cart code in one sample or spreading the info over more of them. One or some samples will be destroyed this way if the file is played, but it won't be even noticable in regular sampling rates (128kbps and above). No protection after harsh downsampling, though.
Pro:
Under circumstances even in waveform you yould possibly still determine the code. In any way information about marking the file could have some impact on users behavior. At least it could provoke a second thought about passing the file on as it is.
How would you suggest me to imprint the code onto the mp3 audio stream?
I would do it by file manipulation via PHP, if possible while serving the file for download.

you haven't discovered anything new: that's watermarking at its finest :-)
there are many MP3 watermarker program out there which imprint your data all over the audio stream. Such watermarks can resist file copy (obviously), upsampling, downsampling (to a given degree), audio trimming and even analog re-recording
check wikipedia: http://en.wikipedia.org/wiki/Steganography#Implementations
section 3 of this site site is on audio: http://www.binary-universe.net/ same author did a project on codeplex.
these also do audio: StegHide mpeStego
and this one:
https://github.com/jcelerier/watermarking/tree/master/src/libwatermark

Related

ID3 Tag while merging MP3s in real time, using PHP and HTTP Partial Content

What we want to do is to add a kind of MP3 preroll to an other MP3 file in real time. That means we have two physical MP3 files on the server which are not merged into one yet, because ffmpeg & Co. take too much time. It has to be in real time to not loose time when someone starts the (web)player. The practical case is to add prerolls to podcast files. What we already did (described below) works, except displaying the correct file duration in audio players.
One of my co-workers did this, so I try to describe as good as possible.
What my coworker already did is telling the header that two files are coming in a row by reading both files and echoing them via PHP. HTTP/1.1 206 Partial Content is used for delivering the "merged" content.
The problem is, that there are still two ID3 Tags from both files and most audio players only read the first one, which occurs wrong duration displays. The only case it works 100% is in VLC after downloading the whole thing. No webplayer, no iTunes etc. can manage the "merged" file duration.
Any idea how to create a "virtual ID3 Tag" in real time and how to remove the existing ones without touching the original files?
There are a lot of inaccurate conclusions you've come to, so let me start by correcting those, which may help you solve the problem.
because ffmpeg & Co. take too much time
FFmpeg can merge these audio streams faster than you can stream to clients for sure. If you're using -codec copy (which you should be in this case), it will handle all the demuxing/muxing for you. And, keep in mind that you can stream directly out of FFmpeg. No need for an intermediary file.
The practical case is to add prerolls to podcast files.
The FFmpeg route is what you want.
What my coworker already did is telling the header that two files are coming in a row by reading both files and echoing them via PHP. HTTP/1.1 206 Partial Content is used for delivering the "merged" content.
That's a bit of a wonky way to do this. You could instead just merge the data and send it directly in a single response.
The problem is, that there are still two ID3 Tags from both files and most audio players only read the first one, which occurs wrong duration displays.
No, the usual ID3 tags don't indicate duration. (There is an extension which does, but this is rarely used.) There is nothing in the bare MP3 stream that indicates duration either. Clients estimate this based on file size and bitrate. The bitrate can change mid-stream, so they usually estimate based on the bitrate of the first couple frames.
Undoubtedly, the problem in your case is incorrect length headers due to the way you're handling this merging, and/or a mismatch of bitrate which causes the length estimate from the player to be wrong.
Any idea how to create a "virtual ID3 Tag" in real time and how to remove the existing ones without touching the original files?
I would absolutely use FFmpeg for this work. If anything, because not all podcasts use MP3. There are plenty of AAC in MP4 podcasts, and a handful of Opus in WebM as well.

Hide text inside audio file with PHP

Is it possible to add a hidden string to an audio file (MP3, mid) via PHP?
I have an online music store and some of my customers resell the songs, and I want to hide his e-mail address in the audio file to identify them.
Audio Files
For real audio files (not MIDI, which is not really an audio file), the best method for this is to use audio watermarking. There are many algorithms and tools (such as AWT) that can be executed from your PHP script to handle this. They work by modifying the audio data in a way that cannot be perceived but can be decoded.
Most of these algorithms can encode the watermark in such a way that they survive re-encoding with other codecs. This is a critical difference from what you are asking for. If you simply were to add an ID3 tag, any tool could remove that. In fact, it's likely your tag would get removed just by tools that read and re-write your ID3 tags. With the information embedded in the actual audio itself however, it will survive. If someone decodes the file and re-encodes with another codec, depending on your watermarking algorithm, the watermark will still survive. Even if someone streams it within another stream, the watermark can survive.
and I want to hide his e-mail address in the audio file to identify them
Rather than embedding personally identifying information, you should store an ID or hash of an ID that you keep in your own database. It might be even better if you generate a new ID for each download so that should you need to find the user who re-sold your files, you can prove when they downloaded it and from what IP address, along with any other information you wish to keep in your database.
MIDI Files
For MIDI, you will have to embed your ID in the metadata of the file. This can be easily defeated, and may not be worth your time at all.

A random pixel on a keyframe. (ffmpeg)

Hello folks of SO!
We're trying to do some very small and simple code in PHP to generate a variation of a video, using always the same file.
The script would have to make a small pixel mark, on random or specific frame of the video file, and this would have to be streamed in real time.
Here's some pseudo code to explain my idea:
$frame = $_GET[frame];
$videofile = 'video.avi';
make_random_red_pixel_mark($videofile, $frame);
Does anyone know if this is possible using ffmpeg? As well, it is of extreamly importance for us, to execute this procedure as fast as possible.
A solution that would imply reprocessing the whole video, won't be useful for our purposes. It should be something like a closed caption, or a quick image / overlay filter that could be applied without an entire video reprocessing. As well, we can't put the overlay using Javascript nor any HTML approach, since the actual manipulation has to be on the video file itself.
The quality, and framerate of the original video, should be kept intact. Perhaps some other PHP module or software that could be execute from PHP using an exec()?
Any recommendation?
Thanks in advance!!
Chris C. Russo
More information:
1) It's possible for us to apply this procedure on any frame we want to, so we could use a "keyframe" in order to avoid the decoding and reencoding of an entire GOP.
2) As previously stated, the video stream would have to flow in real time.
This is a hard problem. The FFmpeg overlay video filter requires re-encoding.
When you change ALMOST anything in a video, you will be dealing with re-encoding of the video. This might be an expensive process depending on the video and on the how hurry you are (if you want real-time, you are in a hurry).
A possible solution for this would be something like this:
Open the INPUT video.
Create the OUTPUT video.
Loop over the packets of the INPUT video until you find the frame you want.
Reading the flags of the video packets (AVPacket structure) you can identify the Group of Pictures of this frame.
Ok, you will have to RE-ENCODE only the frames that belong to this group of pictures. Because a GOP always start with a keyframe, you will be able to do that.
After done, go on reading the packets of the INPUT and writing it to the OUTPUT (transmux).
The process of reading a packet from source and write to destination is called transmux and is very very cheap for live streaming. It's basically a plain copy of bytes. No big deal.
"The hard part here is that you will have to manage a POOL of packets until you identify the GOP where your frame is located. Why? Because you will read all packets AND STORE them in a pool (without decode the packets). When you identify it's a GOP, you will write these packets to your OUTPUT and go on to the next GOP. So you will always have the GOP in memory to be flushed (all packets together). When you identify the target frame you wanna modify. I will have to DECODE THE FRAMES from the beginning of the GOP to the end, modify the frame you want and then REENCODE this GOP! Well very hard!"
For arbitrary videos, this process above may result in a visible difference of quality of encoding in the GOP you reencoded. :-(
If you don't know how to open a video, read the packets, write the packets, etc, etc... you will have to know the basics os FFmpeg.
In order to do that, I suggest you to study this example if you don't know anything about:
Demuxing: http://ffmpeg.org/doxygen/trunk/doc_2examples_2demuxing_8c-example.html
Muxing: http://ffmpeg.org/doxygen/trunk/doc_2examples_2muxing_8c-example.html
This example will teach you how to open the video, identify the audio/video streams and loop over the packets, as well as decoding and reencoding.
Hard job. These examples are in C. You can decide make a plugin for PHP or use a PHP wrapper for FFmpeg.
OTHER SOLUTION IS: If you have flexibility of choose frame, try to reencode only keyframes. Because keyframes are complete "bitmaps". You don't need to deal with GOPs. You will decode and reencode only 1 frame.

Inject metadata or text into WMV with PHP on Linux

I run a website which serves videos to monthly subscribers who can download them. The majority of the videos are WMV and MP4. Is there a PHP or Linux library which would inject metadata or text into the video files without re-encoding the entire file?
My problem is that the videos are pirated and shared on other sites; we are losing money. So, I want to inject the downloader's username so that we can catch the pirates.
I cannot have the movies being re-rendendered/re-encoded for every download because it would put a lot of stress on the server.
I'm looking for some solution that will fopen and fwrite this data to the file.
Any ideas on how to accomplish that or is there any library that can do this?
As Pekka mentioned, inserting meta data won't help you fight piracy. The minute the pirate re-encodes the file, the meta data is lost. In addition, there is software (e.g. TigoTago) which edits meta-data.
A better approach would be to:
Don't allow downloads. Instead, use encrypted streaming.
Allow downloads, but chase down the pirated content; whenever you find the videos on Rapidshare and other file sharing sites, file a complaint.
Because punishing the pirate won't do much. They'll just sign up again with a different name, a different email, and a different prepaid credit card.
If you're still unsure about it; take a look at iTunes. The file which you download cannot be played on any computer which is not authorized (if the file is protected). But, the minute a user converts the file or re-encodes it, the file can be played any where on anything.
edit
And anyways, most pirate shares and torrents are uploaded as MKV or AVI. So most likely, the pirates will be converting and re-encoding it before they upload it; rendering the metadata useless.

Merge two mp3 php

Do you know a class to merge two MP3 files using PHP?
I've found nothing on Google.
If by merging, you mean placing one audio over the other, then please disregard this answer.
If you dont want to re-encode the MP3s, you can probably just append them. I know this worked for MPEG movies, so I guess it could work for MP3s too. Another option would be to add the audo files to a Zip Archive with no compression and then rename the extension to .mp3.
I did a quick test and this
file_put_contents('combined.mp3',
file_get_contents('file1.mp3') .
file_get_contents('file2.mp3'));
worked fine. The ID3 tags will be wrong, but the resulting file contains both audio files. For some other possible gotchas, see the link in Pekka's answer.
Also, some quick googling resulted in
http://www.sourcerally.net/Scripts/20-PHP-MP3-Class
http://codingforums.com/showthread.php?t=169069
and some discussion
http://ask.metafilter.com/21381/Merge-mp3s-with-PHP
For anyone interested in doing the same thing now, you can use the following library that I wrote (refactored?):
https://github.com/falahati/PHP-MP3
composer require falahati/php-mp3
Merge two MP3 file:
$audio1 = \falahati\PHPMP3\MpegAudio::fromFile("1.mp3")->stripTags();
$audio2 = \falahati\PHPMP3\MpegAudio::fromFile("2.mp3")->stripTags();
$audio1->append($audio2)->saveFile("3.mp3");
Please note that this is an MP3 parser library and it does not encode, decode or re-encode MP3 files. This solution is essentially the same as others here but always results in a structurally correct and standard MP3 file.
-- In answer to the comment about the invalid duration of the file:
MP3 files have no header and only consists of MPEG frames. This library keeps the MPEG frame headers (since it won't be playable without those) and therefore the problem described here is not entirely true.
However, from the point of view of a player or a tool that needs to extract the duration of an MP3 file, in the absence of an ID3 tag, the whole file should be read and calculate the duration frame by frame. This is both calculation-intensive and memory-intensive, especially for big files.
Therefore many tools might try to read the first frame and guess the number of total frames based on the total size of the file and simply calculate the possible duration of the file from this information and based on the properties of the first frame. This is alright by it-self and should work with no to little difference to the real file's duration.
The real problem arises when you try to merge two hugely different MP3 files together. Since this library does no re-encode the files it won't change the frames and just simply adds them next to each other trusting the player to read the MP3 frame header for each frame independently of other frames. This is not the case with some players and tools since they tend to ignore each frame property in favor of performance by only reading the properties of the first frame and expecting all other frames to be similar.
This is where your problem with duration arises from and not from a bug or lack of feature in this library. You simply need to provide the library with similar files in terms of properties (bitrate, etc); otherwise, you are leaving the fate of your file in the hand of player's MP3 decoder implementation.
Other issues with hugely different files sewed together via this library and bad player implementations contain, fast or slow-paced playback, error while playing, distorted playback, etc. So make sure your files are as close to each other as possible if the file's portability is something you care about (sharing the file for download maybe) or use a compatible player if it is not (in my tests, Chrome, Firefox and Telegram ware compatible; don't know and don't remember about the others).
This is not possible. There is no implementation of the MP3 codec in PHP. You will need to use an external command-line tool to do this. (Which, depending on your server configuration, you can execute from within PHP as #ceejayoz says.)
See these questions for solutions:
Merging MP3 files in Linux Debian using PHP
What is the best way to merge mp3 files?
If the .mp3 files are just MPEG-1 or MPEG-2 Layer III audio, then the files can just be concatenated. There is no real concept of a header for the whole file. Each frame has a header followed by data, and the file is just comprised of a sequence of frames, which is called the bitstream. The bitrate, stereo mode, etc, do not necessarily have to be the same within a bitstream, so you can concatenate dissimilar files. The Wikipedia article explains this, but I think the spec actually is easier to understand.
ID3 tags, or an other data, within the file (which technically renders it a non-compliant bitstream) may muck things up on the decoder end.
The spec for MPEG-1 and MPEG-2 audio is actually pretty simple. Writing a parser to chunk a file into frames, and then interpreting the headers is not that much work. The last time I did this, it only took an hour or two.
The ID3 spec isn't that complicated either, so I suspect writing some code to strip out the tags before concatenation should be easy, but I have never done this.
The getID3() library (http://getid3.sourceforge.net/) may provide some guidance, too. It has been a while since I have used it, but it may also support opening MP3s and stripping out the ID3 tags already.
HTH
Important things to remember:
The bit rates must match. It's also a good idea to ensure the rate (Hz) and stereo/mono are matched (I used Audacity).
The Content-length header be the length of both files.
Here's a sample from my text-to-speech project. I needed to add a 1 second silence at the end of MP3 audio that was generated dynamically:
$output_audio = textToMP3("Hello World"); // Original audio
$silent_audio = file_get_contents("silence.mp3"); // 1 second silence
$content_length = strlen($output_audio) + strlen($silent_audio);
// Output the audio stream
header('Content-type: audio/mpeg');
header('Content-length: ' . $content_length);
header('Cache-Control: no-cache');
header("Pragma: no-cache");
header("Expires: 0");
echo $audio . $silent_audio;

Categories