IMFSourceReaderCallback::OnReadSample Function - ms-media-foundation

To read samples from your webcam and write them to file you can implement IMFSourceReaderCallback and the call back function OnReadSample will send IMFSample *pSample with some others parameters like the timestamp you can use them with ISinkWriter to write them on file(You can check MSDN example MFCaptureToFile Sample )
STDMETHODIMP OnReadSample(
HRESULT hrStatus,
DWORD dwStreamIndex,
DWORD dwStreamFlags,
LONGLONG llTimestamp,
IMFSample *pSample
);
I have set my encoded parameters to H264 .I convert pSample to rawdata(set of bytes) and removed ISinkWriter.
I have a tricky question *"is IMFSample pSample encoded or they become encoded inside ISinkWriter as when I convert them to RawData I got a huge file so are they encoded?" One more question how can I test them after writing them to file(they are in a raw format)

The sample will be in a raw format such as YUV or RGB. You can't set the output media type to H264 on a video device source reader (unless that device happens to natively support H264). When you introduce the SinkWriter with an .mp4 file as the destination the Media Foundation will take care of resolving the topology which in this case would mean including the H264 Media Foundation Transform.
One way I use to test the raw output from a SourceReader is to specify an output format of MFVideoFormat_IYUV and then after writing to a file stream use ffmpeg to extract a jpeg or convert it to a avi video file.
std::ofstream outputBuffer("rawframes.yuv", std::ios::out | std::ios::binary);
IMFMediaBuffer *buf = NULL;
DWORD bufLength;
pSample->ConvertToContiguousBuffer(&buf);
buf->GetCurrentLength(&bufLength);
printf("Writing sample %i, sample time %i, sample duration %i, sample size .\n", sampleCount, llVideoTimeStamp, llSampleDuration);
byte *byteBuffer;
DWORD buffCurrLen = 0;
DWORD buffMaxLen = 0;
buf->Lock(&byteBuffer, &buffMaxLen, &buffCurrLen);
outputBuffer.write((char *)byteBuffer, bufLength);
outputBuffer.flush();
And then the ffmpeg commands:
ffmpeg -vcodec rawvideo -s 640x480 -pix_fmt yuv420p -i rawframes.yuv -vframes 1 output.jpeg
ffmpeg -vcodec rawvideo -s 640x480 -pix_fmt yuv420p -i rawframes.yuv out.avi
Sample console app that uses the above snippet available on github.

Related

FFmpeg: how to stream multiple http outputs

I'm assigned to search for a solution to stream more than one http output in ffmpeg. I tried the code below which uses pipe, but only the last output works, other ones don't work. The solutions I tried with tee muxer also couldn't work. Any idea how can I do that?
ffmpeg -re -i sample1.mp3 -i sample2.mp3 -filter_complex amix=inputs=2 -f mp3 pipe:1 | ffmpeg -f mp3 -re -i pipe:0 -c copy -listen 1 -f mp3 http://127.0.0.1:4000 -c copy -listen 1 -f mp3 http://127.0.0.1:4010
The code I tried with tee muxer is below:
ffmpeg -re -i sample1.mp3 -i sample2.mp3 -filter_complex amix=inputs=2 -c:a mp3 -f tee "[listen=1:f=mp3]http://127.0.0.1:4000|[listen=1:f=mp3]http://127.0.0.1:4010"
edit: shared the log with code.
ffmpeg -loglevel debug -hide_banner -re -i sample1.mp3 -filter_complex asplit=2 -c:a mp3 -listen 1 -f mp3 http://127.0.0.1:4000 -c:a mp3 -listen 1 -f mp3 http://127.0.0.1:4010
Splitting the commandline.
Reading option '-loglevel' ... matched as option 'loglevel' (set logging level) with argument 'debug'.
Reading option '-hide_banner' ... matched as option 'hide_banner' (do not show program banner) with argument '1'.
Reading option '-re' ... matched as option 're' (read input at native frame rate; equivalent to -readrate 1) with argument '1'.
Reading option '-i' ... matched as input url with argument 'sample1.mp3'.
Reading option '-filter_complex' ... matched as option 'filter_complex' (create a complex filtergraph) with argument 'asplit=2'.
Reading option '-c:a' ... matched as option 'c' (codec name) with argument 'mp3'.
Reading option '-listen' ... matched as AVOption 'listen' with argument '1'.
Reading option '-f' ... matched as option 'f' (force format) with argument 'mp3'.
Reading option 'http://127.0.0.1:4000' ... matched as output url.
Reading option '-c:a' ... matched as option 'c' (codec name) with argument 'mp3'.
Reading option '-listen' ... matched as AVOption 'listen' with argument '1'.
Reading option '-f' ... matched as option 'f' (force format) with argument 'mp3'.
Reading option 'http://127.0.0.1:4010' ... matched as output url.
Finished splitting the commandline.
Parsing a group of options: global .
Applying option loglevel (set logging level) with argument debug.
Applying option hide_banner (do not show program banner) with argument 1.
Applying option filter_complex (create a complex filtergraph) with argument asplit=2.
Successfully parsed a group of options.
Parsing a group of options: input url sample1.mp3.
Applying option re (read input at native frame rate; equivalent to -readrate 1) with argument 1.
Successfully parsed a group of options.
Opening an input file: sample1.mp3.
[NULL # 00000216ab345b80] Opening 'sample1.mp3' for reading
[file # 00000216ab346180] Setting default whitelist 'file,crypto,data'
[mp3 # 00000216ab345b80] Format mp3 probed with size=4096 and score=51
id3v2 ver:4 flags:00 len:134
[mp3 # 00000216ab345b80] pad 576 576
[mp3 # 00000216ab345b80] Skipping 0 bytes of junk at 561.
[mp3 # 00000216ab345b80] Before avformat_find_stream_info() pos: 561 bytes read:32768 seeks:0 nb_streams:1
[mp3 # 00000216ab345b80] demuxer injecting skip 1105 / discard 0
[mp3float # 00000216ab34f3c0] skip 1105 / discard 0 samples due to side data
[mp3float # 00000216ab34f3c0] skip 1105/1152 samples
[mp3 # 00000216ab345b80] All info found
[mp3 # 00000216ab345b80] After avformat_find_stream_info() pos: 22065 bytes read:32768 seeks:0 frames:50
Input #0, mp3, from 'sample1.mp3':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2mp41
encoder : Lavf58.45.100
Duration: 00:12:58.48, start: 0.025057, bitrate: 128 kb/s
Stream #0:0, 50, 1/14112000: Audio: mp3, 44100 Hz, stereo, fltp, 128 kb/s
Metadata:
encoder : Lavc58.91
Successfully opened the file.
[Parsed_asplit_0 # 00000216ab34fc80] Setting 'outputs' to value '2'
Parsing a group of options: output url http://127.0.0.1:4000.
Applying option c:a (codec name) with argument mp3.
Applying option f (force format) with argument mp3.
Successfully parsed a group of options.
Opening an output file: http://127.0.0.1:4000.
Matched encoder 'libmp3lame' for codec 'mp3'.
Last message repeated 1 times
[http # 00000216ab44d980] Setting default whitelist 'http,https,tls,rtp,tcp,udp,crypto,httpproxy,data'
FFmpeg can output multiple outputs by default (w/out using the tee muxer):
ffmpeg -re -i sample1.mp3 -i sample2.mp3 \
-filter_complex amix=inputs=2,asplit \
-c:a mp3 -listen 1 f=mp3 http://127.0.0.1:4000 \
-c:a mp3 -listen 1 f=mp3 http://127.0.0.1:4010
Because you need to route the filtergraph output to 2 streams, you need to add asplit filter to your graph, and all you need to do is to have 2 output option sequences in series.
edited: fixed -listen option as pointed out by op

Splitting m4a into multiple files with ffmpeg

I have an audio file (.m4a) and want to split it into smaller pieces using ffmpeg. All answers I have seen do something along one of the following two possibilities:
ffmpeg -i inputFile -map 0 -f segment -segment_time 60 -c copy "$output%03d.m4a
or
ffmpeg -i inputFile -acodec copy -ss start_time -to end_time outputFile
With 1. the first file is fine. From the second file on, I just get a minute of silence in quicktime, and in VLC the file plays but the timing is odd: for example the second file should have second 0 equals to second 60 in the original file. However in vlc it starts playing on second 60 and goes on to second 120.
With 2. I have to set start times and end for each file, unfortunately I notice a small jump when I play one after the other, so it seems as if some miliseconds are lost.
There are definitely a few old questions asked around this, but none of them actually helped me with this.
Quicktime probably doesn't like files starting with a timestamp other than 0.
Use
ffmpeg -i inputFile -map 0 -f segment -segment_time 60 -reset_timestamps 1 -c copy "$output%03d.m4a

image -> video -> image not lossless using avconv

I'm trying to test the amount of information lost with some different video codecs. I've got a python script which uses PyPNG to write a series of 8 bit RGB images. I then encode it using avconv, for instance
avconv -r 1 -i ../frames/data%03d.png -c:v ffv1 -qscale:v 0 -r 1
outffv1.avi
I then decode this back into pngs like so
avconv -r 1 -i outffv1.avi -r 1 ./outffv1/frame%03d.png
But when I compare the images before and after the video compression, they are different (mean absolute error of ~~15%). The thing that is confusing me is that this is true (give or take) independent of the codec.
For instance, I get similar answers for libtheora for a range of qscale values.
The png encoding i.e. write to png, and immediately load back in without and video compression step, is lossless.
UPDATE - more precise worked example:
Single input frame here: https://www.dropbox.com/s/2utk1xs2t8heai9/data001.png?dl=0
Encoded to video like this: avconv -r 1 -i ./frames/data%03d.png -c:v ffv1 -qscale:v 0 -r 1 outffv1.avi
resultant video here: https://www.dropbox.com/s/g1babae2a41v914/outffv1.avi?dl=0
decoded to a png again here: https://www.dropbox.com/s/8i8zg1qn7dxsgat/out001.png?dl=0
using this command: avconv -r 1 -i outffv1.avi -qscale:v 31 -r 1 out%03d.png
and image magick differenced like this
compare out001.png ./frames/data001.png diff.png
to give this (non-zero) diff
https://www.dropbox.com/s/vpouk54p0dieqif/diff.png?dl=0
Your video file most likely uses the YUV color format. PNG uses RGB. The conversion of the color is not a lossless process.

Why the Target Duration of the created segments are not the one i specified

I am using the following command
ffmpeg -i Apple.ts -map 0:0 -map 0:1 -c copy -f segment -segment_time 10 -segment_list test.m3u8 -segment_format ts 'fileSequence%d.ts'
The files do get segmented but the values are not precise. see in the .m3u8 generated below the target duration is 12 but i specified 10
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-ALLOWCACHE:1
#EXTINF:11.478100,
fileSequence0.ts
#EXTINF:10.410400,
fileSequence1.ts
#EXTINF:11.745067,
fileSequence2.ts
#EXTINF:7.841167,
fileSequence3.ts
#EXTINF:8.024678,
fileSequence4.ts
#EXT-X-TARGETDURATION:12
#EXT-X-ENDLIST
Also if i dont want the floting point duration how do i do it?
To get strict duration you need to ensure your input file has been encoded with a strict I picture rate. Ensure you have set keyframe interval to 10 seconds and sc_threshold to 0 while encoding the original mp4.with ffmpeg. Then run your segmentation command. This will give you exact 10 second segments.
Otherwise ffmpeg will try and cut around the 10 second mark ( or whatever duration you have given ) at the closes I picture it can find.

cut exact time range from mp3/ogg

I have a heap of audio files on a CDN. Those are mp3's and ogg vorbises, in parallel. Those files are each worth about one hour of playback. I need to extract arbitrary parts from those files: I am given a filename (I can choose if I use the mp3 or ogg version) and two timestamps and I need the audio exactly between the given time positions. I don't want to download the whole file, so I think of using the Range http header.
I have complete control over the audio files, so I encoded them in fixed bitrate, to be able to estimate which bytes I should reach for. However, both formats use frames (or pages in vorbis's case), which must be decoded atomically.
The program I write is in Perl. I tried downloading a part of the file where I believe the given window to be contained, and then using Audio::Mad and Ogg::Vorbis::Decoder to parse the audio file fragments. However, both seem to fail to process the fragments, and only succeed when I serve an integral file.
So my question is: How can I get an exact span of an audio file without downloading the whole thing?
Answering "cut exact time range from mp3/ogg" - You can check out if the following fits Your needs:
ffmpeg -i InFile -vn -acodec copy -ss 00:00:00 -t 00:01:32 -threads 0 OutFile
where ss - start time, t - duration. It cuts indeed - no re-compressions.

Resources