-3

I've been attempting to write code that returns the byte data of a thumbnail for the very first frame of a local video file for a few days now with no success. No GUI or rendering is required for this particular bit of code - I simply need to get a thumbnail of the very first video frame, and get the byte data of that thumbnail. (For context, I'm writing a Flutter plugin that will call this code through a method channel - it will pass in the file path, and the bytes of the thumbnail are expected to be returned from the method channel call)

I have attempted to do this with no success using the MediaFoundation library, relying on the confusing code in this example provided by Microsoft. (It is confusing to me because, as I mentioned above, I don't need to render the thumbnail on the screen, nor do I need more than one thumbnail from the video - I only need the very first.) After spending many hours over the course of several days fighting with this code, I've come to the conclusion that this library is not useful for me since it seems to involve rendering in some way at every level - even the GetDIBits function, which appears to be the best way to get the bits out of a Bitmap, relies upon having a handle, which seems to come from the existing application Window, which is not present in my particular case.

I have scoured the internet looking for a simple way to accomplish doing this and have come up with nothing. I've read so many forum posts and documentation from Microsoft, and the whole thing is driving me absolutely crazy! There must be a simple solution to this problem, right? There has to be a way to do this that doesn't involve rendering.

I've also tried working with std::fstream with no success.

GroovinChip
  • 339
  • 4
  • 17
  • Video encoding/decoding is not simple, I'm not sure why you expect a simple solution for your specific goal – François Andrieux Apr 04 '22 at 14:57
  • *What is the absolute simplest and shortest way* -- Questions with "what is the shortest" or "what is the simplest" are opinion-based questions, and are off-topic. Being "shortest" and "simplest" depends on who you ask and what is being done. If you ask "is there a way to do this using xyz...", that is a different situation. – PaulMcKenzie Apr 04 '22 at 14:58
  • "There has to be a way to do this without rendering" - well, no. What you describe is exactly rendering: get frame N, just for the special case where N=0. But there's nothing in video which makes frame 0 special. – MSalters Apr 04 '22 at 15:02
  • @FrançoisAndrieux I'm not encoding or decoding anything. I just want the bytes for the first frame of video. – GroovinChip Apr 04 '22 at 15:21
  • @PaulMcKenzie I AM asking what the right way to accomplish this is. Sorry if my wording offended you. I've updated the title. – GroovinChip Apr 04 '22 at 15:21
  • @GroovinChip To get the first frame of a video, you need to decode that frame from whatever source you are reading from. Videos are (almost) never stored or transmitted as a series of bitmaps, they are always heavily compressed. Reading a frame of video from a source IS decoding that frame from the source. – François Andrieux Apr 04 '22 at 15:25
  • @FrançoisAndrieux I see, thank you for explaining. Do you know what the right way to do this is? – GroovinChip Apr 04 '22 at 15:26
  • @GroovinChip *a local video file* -- Format? Compression that's used? – PaulMcKenzie Apr 04 '22 at 15:34
  • @PaulMcKenzie the goal here is to create a Flutter plugin that can generate thumbnails for any video that is passed to it, so the format & compression could be anything. My test file happens to be an mp4, idk what kind of compression it has. Am I to understand from your question that format & compression are required to be known in order to generate thumbnails? – GroovinChip Apr 04 '22 at 15:41
  • @GroovinChip I am not an expert on video formats, but non-video image formats can be determined by looking at certain aspects of the file (usually the first few bytes of the file can determine the format). I am sure the same can be said for video formats -- how do third-party apps know what formats videos are without playing them? – PaulMcKenzie Apr 04 '22 at 15:43
  • @PaulMcKenzie yeah I hear what you're saying. But is knowledge of the video format required to get a thumbnail for the video in question? – GroovinChip Apr 04 '22 at 15:47
  • @GroovinChip You have to research on the various formats and see how they are determined. For non-video formats, it's basically a big `switch` or `if` statement, going through the various signatures for each image format to determine what the format is. It isn't "automatic" -- you have to know what to look for (which is why this is farmed out to third-party libraries whose job is to do image processing). If you want to get into the business of processing images (video or non-video), prepare for a long learning curve. – PaulMcKenzie Apr 04 '22 at 15:50
  • @PaulMcKenzie: There's no need for custom code or third party libraries. Windows comes with the function out of the box: `IThumbnailProvider::GetThumbnail()`, via `IInitializeWithFile`. – MSalters Apr 04 '22 at 16:11
  • @PaulMcKenzie yes, I've seen `IThumbnailProvider::GetThumbnail` via `IInitializeWithFile`, but I don't understand how to use them, which is why I went searching for example code, and the only thing I found was that VideoThumbnail example in the Classic Samples repo. Would you mind sharing some example code that would illustrate the proper usage, please? – GroovinChip Apr 04 '22 at 16:15

1 Answers1

1

It seems you're misreading the documentation. In Win32, there are many things that are called "handles". There's for instance a "window handle", HWND. That's what your application window would have.

But GetDIBits takes another sort of handle, a "handle to a device context" or HDC. These are often related; there's even a WindowFromDC to get one from the other. But you just want to paint to a memory buffer, it doesn't need to be visible. In that case, you can use CreateCompatibleBitmap(). Note the example on that page using it in conjunction with CreateCompatibleDC - this is how you get an HDC for that bitmap.

MSalters
  • 173,980
  • 10
  • 155
  • 350
  • how would I even get an HDC to pass to `WindowFromDC`? And what would even be the proper way to use these functions? I'm still lost about what the right way to get the thumbnail from the video is. The closest I've gotten, I think, is this code (slightly modified to fix errors): http://cplusplus.com/forum/windows/100661/ in conjunction with code from this answer: http://cplusplus.com/forum/windows/100661/. Here it seems that I am actually getting back an array of bytes, but they don't seem to be valid image data (Flutter cannot render the bytes as an image) – GroovinChip Apr 04 '22 at 15:18
  • @GroovinChip: The votes on the question aren't mine, but I understand them. You seem to be rather in over your head. You don't have an `HWND`, and I'm not sure why you want one? The point of this answer is since you don't yet have an HDC, but you apparently need one for that code snippet. So this answer says how you can create an HDC without having an HWND. – MSalters Apr 04 '22 at 15:55
  • I guess what's confusing me is that `CreateCompatibleDC` returns an `HDC`, but it also requires one as a parameter. How can I pass an `HDC` in if I don't have one already? Could you perhaps share some example code that could help me understand how I'd use the functions you mentioned all together? Seeing practical code helps me better understand descriptions for such code. – GroovinChip Apr 04 '22 at 16:13
  • @gro [`CreateCompatibleDC`](https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createcompatibledc) doesn't require a DC. You can pass `NULL` to get a DC that's *"compatible with the application's current screen"*. Alternatively you can pass the `HDC` returned by [`GetDC`](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdc). Again, you don't need an `HWND` here. If you pass `NULL` here it *"retrieves the DC for the entire screen"*. – IInspectable Apr 04 '22 at 20:24