I am trying to use the IMFSourceResolver::CreateObjectFromByteStream method to create a IMFMediaSource instance for a DRM protected WMA file. I am adapting the ProtectedPlayback sample from the Windows SDK as a playground. The end goal I wish to achieve is to have the playback process fed by a custom implementation if IMFByteStream that I will write.
However, I cannot get either my simple IMFByteStream implementation or the implementations returned by the MFCreateFile function to work. Each returns a HRESULT of MF_E_UNSUPPORTED_BYTESTREAM_TYPE when passed to CreateObjectFromByteStream.
I tested the sample project in its default state (using CreateObjectFromUrl on a file) with a DRM protected WMA file and it worked fine. The file is not corrupt and the license is valid. I don't understand why substituting this bit of code with CreateObjectFromByteStream( MFCreateFile() ) does not work. I have been able to find little documentation that covers using custom byte streams or what the resolver expects from a byte stream instance.
If anybody has any experience with this stuff or any idea what I am doing wrong, some pointers would be appreciated.
The code I am using is here:
IMFByteStream* stream = NULL;
HRESULT hr2 = MFCreateFile(
MF_ACCESSMODE_READ,
MF_OPENMODE_FAIL_IF_NOT_EXIST,
MF_FILEFLAGS_NONE,
L"C:\\IFB.wma",
&stream);
CHECK_HR(hr = pSourceResolver->CreateObjectFromByteStream(
stream,
NULL,
MF_RESOLUTION_MEDIASOURCE,
NULL,
&ObjectType,
&pSource));
I've not included the whole thing because its basically the same as the sample, I've only changed this part.
Thanks,
Steve
#pisomojado
Thanks for the response, I totally forgot I had posted this question.
The problem was, if I remember correctly, that CreateObjectFromByteStream needs a way to identify the content type. You can either do this by passing in a URL as well as the byte stream instance (pwszURL parameter) or by making the byte stream class implement IMFAttributes and handle the call to GetAllocatedString that asks for the content type. Since I was doing neither of these things, the resolver was just rejecting the stream.
I would have thought that the resolver would attempt to recognize the stream content type via the first few bytes like you suggested in your answer, but for me it did not appear to do so. Not sure why this is, but nevermind.
Steve
Some ideas for debugging what's going on here:
First off, do an IMFSourceResolver::CreateObjectFromUrl on your c:\ifb.wma file; make sure that's happy.
Assuming it is, then it's on to looking at what happens in your IMFByteStream while inside the CreateObjectFromByteStream call. Typically, CreateObjectFromByteStream will try to read a couple bytes off the beginning of the IMFByteStream, since there's usually some kind of identifying byte sequence there. Set some breakpoints or do some logging from your IMFByteStream::[Begin]Read to see what you're being asked for, and whether you're faithfully delivering the right bytes.
FWIW, all WMA files (and WMV, and ASF) start like this (it's the ASF header GUID).
30 26 b2 75 8e 66 cf 11 a6 d9 00 aa 00 62 ce 6c
Related
I have a raw h264 stream, and would like to decode it using directx11.
I'm following these docs, and am the section to actually start decoding frames. (ie Calling BeginDecodeFrame())
I'm also following some advice from this question:
Which references an older verson of the same docs I linked previously. Anyway, it's saying that I need to fill some buffers:
D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS
D3D11_VIDEO_DECODER_BUFFER_INVERSE_QUANTIZATION_MATRIX
D3D11_VIDEO_DECODER_BUFFER_BITSTREAM
D3D11_VIDEO_DECODER_BUFFER_SLICE_CONTROL
I'm relatively familiar with h264, and understand I can get this information from parsing the NALU's. That being said, I don't want to manually parse the h264 packets themselves, It seems like there should be some kind of convenience method to do this for me.. So is there??
Coming from the Mac world, I can just call: CMVideoFormatDescriptionCreateFromH264ParameterSets with the PPS and SPS data and that'll handle it for me.
A follow up on that, how exactly do I "Fill These Buffers" ?
HRESULT GetDecoderBuffer(
[in] ID3D11VideoDecoder *pDecoder,
[in] D3D11_VIDEO_DECODER_BUFFER_TYPE Type,
[out] UINT *pBufferSize,
[out] void **ppBuffer
);
The function signature expects an out param of (void**), so if I wanted to fill D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS, how do exactly to do I fill it with the parsed data? Do I need to assign a pointer to DXVA_PictureParameters and then cast it as a void** like: (void**)&myPictureParamets when I call the function?
The linked docs state:
Direct3D 11 uses the same data structures as DXVA 2.0 for decoding operations.
So I'm kind of guessing on DXVA_PictureParameters being the correct struct to use here.
I was expecting this to be easier than it has been! :P
So... I'm dealing with a system that has input data coming in buffers (i.e. NOT a file). I want to determine which decoder to create to decompress an audio stream (MP3, WAV, OGG, ...) So obviously I do not know the input format.
I found out that I could determine the format using the av_probe_input_format[23]() functions. That part works great, I get a format pointer that matches the files that I use as input.
AVInputFormat * format(av_probe_input_format3(&pd, true, &score));
I can print the format->name and format->long_name and these are the correct type (so the detection is working as expected).
Now, I'm trying to understand how to convert that AVInputFormat * into a AVCodec * so I can call avcodec_alloc_context3(codec) to create the actual audio decoder.
I found a couple of functions, which I used like so:
AVCodecID const codec_id(av_codec_get_id(format->codec_tag, format->raw_codec_id));
AVCodec * codec(avcodec_find_decoder(codec_id));
Problem 1. the raw_codec_id field is marked as "private" (should not access/use anywhere in your client's code).
Problem 2. the first function always returns AV_CODEC_ID_NONE (0) so of course the second call fails each time.
Am I doing something wrong? Is there is way to instead create a generic decode that will automatically detect the type of audio I have as input? (that is, would that be the only way to make that work?)
Okay, so the fact is that trying to use these functions directly is pretty much futile. The problem I have with the design is that it forces me to actually have a callback and that callback forces me to have a thread (i.e. I have to somehow feed data from a stream, not a file or such!)
So I can use the avformat_open_input() as mentioned by Gyan, only I have to have my own AVIOContext. I was hoping I could just call functions with my incoming data and avoid the pipeline concept. The issue here is some background processes could be servers that use fork() and thus you need to be really careful (i.e. fork() is not friendly with threads).
I am trying to debug a problem with some code that uses zlib 1.2.8. The problem is that this larger project can make archives, but runs into Z_DATA_ERROR header problems when trying to extract that archive.
To do this, I wrote a small test program in C++ that compresses ("deflates") a specified regular file, writes the compressed data to a second regular file, and extracts ("inflates") to a third regular file, one line at a time. I then diff the first and third files to make sure I get the same bytes.
For reference, this test project is located at: https://github.com/alexpreynolds/zlib-test and compiles under Clang (and should also compile under GNU GCC).
My larger question is how to deal with header data correctly in my larger project.
In my first test scenario, I can set up compression machinery with the following code:
z_error = deflateInit(this->z_stream_ptr, ZLIB_TEST_COMPRESSION_LEVEL);
Here, ZLIB_TEST_COMPRESSION_LEVEL is 1, to provide best speed. I then run deflate() on the z_stream pointer until there is nothing left that comes out of compression.
To extract these bytes, I can use inflateInit():
int ret = inflateInit(this->z_stream_ptr);
So what is the header format, in this case?
In my second test scenario, I set up the deflate machinery like so:
z_error = deflateInit2(this->z_stream_ptr,
ZLIB_TEST_COMPRESSION_LEVEL,
ZLIB_TEST_COMPRESSION_METHOD,
ZLIB_TEST_COMPRESSION_WINDOW_BITS,
ZLIB_TEST_COMPRESSION_MEM_LEVEL,
ZLIB_TEST_COMPRESSION_STRATEGY);
These deflate constants are, respectively, 1 for level, Z_DEFLATED for method, 15+16 or 31 for window bits, 8 for memory level, and Z_DEFAULT_STRATEGY for strategy.
The former inflateInit() call does not work; instead, I must use inflateInit2() and specify a modified window bits value:
int ret = inflateInit2(this->z_stream_ptr, ZLIB_TEST_COMPRESSION_WINDOW_BITS + 16);
In this case, the window bits value is not 31 as in the deflateInit2() call, but 15+32 or 47.
If I use 31 (or any other value than 47), then I get a Z_DATA_ERROR on subsequent inflate() calls. That is, if I use the same window bits for the inflateInit2() call:
int ret = inflateInit2(this->z_stream_ptr, ZLIB_TEST_COMPRESSION_WINDOW_BITS);
Then I get the following error on attempting to inflate():
Error: inflate to stream failed [-3]
Here, -3 is the same as Z_DATA_ERROR.
According to the documentation, using 31 with deflateInit2() should write a gzip header and trailer. Thus, 31 on the following inflateInit2() call should be expected to be able to extract the header information.
Why is the modified value 47 working, but not 31?
My test project is mostly similar to the example code on the zlib site, with the exception of the extraction/inflation code, which inflates one z_stream chunk at a time and parses the output for newline characters.
Is there something special about running inflate() only when a new buffer of extracted data is asked for — like header information going missing between inflate() calls — as opposed to running the whole extraction in one pass, as in the zlib example code?
My larger debugging problem is looking for a robust way to extract a chunk of zlib-compressed data only on request, so that I can extract data one line at a time, as opposed to getting the whole extracted file. Something about the way I am handling the zlib format parameter seems to be messing me up, but I can't figure out why or how to fix this.
deflateInit() and inflateInit(), as well as deflateInit2() and inflateInit2() with windowBits in 0..15 all process zlib-wrapped deflate data. (See RFC 1950 and RFC 1951.)
deflateInit2() and inflateInit2() with negative windowBits in -1..-15 process raw deflate data with no header or trailer. deflateInit2() and inflateInit2() with windowBits in 16..31, i.e. 16 added to 0..15, process gzip-wrapped deflate data (RFC 1952). inflateInit2() with windowBits in 32..47 (32 added to 0..15) will automatically detect either a gzip or zlib header (but not raw deflate data), and decompress accordingly.
Why is the modified value 47 working, but not 31?
31 does work. I did not try to look at your code to debug it.
Is there something special about running inflate() only when a new
buffer of extracted data is asked for — like header information going
missing between inflate() calls — as opposed to running the whole
extraction in one pass, as in the zlib example code?
I can't figure out what you're asking here. Perhaps a more explicit example would help. The whole point of inflate() is to decompress a chunk at a time.
I am developing in C++ using Boost.Asio. I want to be able to base64 decode data and since Boost.Asio links to openssl I want to use it's functions to do so and not add an extra dependency(eg crypto++). I have found this code here that shows how to do it. (change int finalLen = BIO_read(bmem, (void*)pOut, outLen); to inLen )
I don't know if it works. I just pass to it some test data that I verify with an online decoder found here(2) (select decode safely as text and count the symbols). The test string I use is this one: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" (without the ""). Both the online decoder and a quick crypto++ implementation return 23 chars. But the code I mentioned above using openssl returns 0. Am I doing something wrong? Is openssl suitable for base64 decoding?
Please provide me a solution (if one exists). Thanks for you time.
pff sorry my mistake. I forgot to allocate memory for pOut. The code seems to work now.
Is it possible to change the frame rate of an avi file using the Video for windows library? I tried the following steps but did not succeed.
AviFileInit
AviFileOpen(OF_READWRITE)
pavi1 = AviFileGetStream
avi_info = AviStreamInfo
avi_info.dwrate = 15
EditStreamSetInfo(dwrate) returns -2147467262.
I'm pretty sure the AVIFile* APIs don't support this. (Disclaimer: I was the one who defined those APIs, but it was over 15 years ago...)
You can't just call EditStreamSetInfo on an plain AVIStream, only one returned from CreateEditableStream.
You could use AVISave, then, but that would obviously re-copy the whole file.
So, yes, you would probably want to do this by parsing the AVI file header enough to find the one DWORD you want to change. There are lots of documents on the RIFF and AVI file formats out there, such as http://www.opennet.ru/docs/formats/avi.txt.
I don't know anything about VfW, but you could always try hex-editing the file. The framerate is probably a field somewhere in the header of the AVI file.
Otherwise, you can script some tool like mencoder[1] to copy the stream to a new file under a different framerate.
[1] http://www.mplayerhq.hu/
HRESULT: 0x80004002 (2147500034)
Name: E_NOINTERFACE
Description: The requested COM interface is not available
Severity code: Failed
Facility Code: FACILITY_NULL (0)
Error Code: 0x4002 (16386)
Does it work if you DON'T call EditStreamSetInfo?
Can you post up the code you use to set the stream info?