Error writing file with Media Foundation while file is being opened

nthamy 6 Reputation points
2021-09-24T02:10:35.163+00:00

I use Media Foundation to write files. The program is as follows:

#include <windows.h>
 #include <windowsx.h>
 #include <comdef.h>
 #include <stdio.h>
 #include <mfapi.h>
 #include <mfidl.h>
 #include <mfreadwrite.h>
 #include <Mferror.h>
 #include <mfplay.h>
 #include <codecapi.h>
 #include <atlcomcli.h>
 #pragma comment(lib, "ole32")
 #pragma comment(lib, "mfplat")
 #pragma comment(lib, "mfreadwrite")
 #pragma comment(lib, "mfuuid")

 int main()
 {
  HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  hr = MFStartup(MF_VERSION);

  IMFMediaType *pMediaType;
  IMFMediaType *pMediaTypeOut;
  IMFSourceReader *pSourceReader;
  IMFAttributes *pAttributes;
  IMFSinkWriter *pSinkWriter;
  IMFMediaType *pCurrentMediaType;
  LONGLONG nDruration = 300000000;

  hr = MFCreateSourceReaderFromURL(L"./in.mp4", NULL, &pSourceReader);
  pSourceReader->SetStreamSelection(MF_SOURCE_READER_FIRST_VIDEO_STREAM, TRUE);

  IMFMediaType *pPartialType;
  MFCreateMediaType(&pPartialType);
  hr = pPartialType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
  hr = pPartialType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_NV12);
  hr = pSourceReader->SetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM, nullptr, pPartialType);
  hr = pSourceReader->GetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM, &pPartialType);
  hr = pSourceReader->SetStreamSelection(MF_SOURCE_READER_FIRST_VIDEO_STREAM, TRUE);

  hr = MFCreateMediaType(&pMediaTypeOut);
  hr = pMediaTypeOut->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
  hr = pMediaTypeOut->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_HEVC);
  hr = pMediaTypeOut->SetUINT32(MF_MT_AVG_BITRATE, 512000);
  hr = pMediaTypeOut->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive);
  hr = MFSetAttributeRatio(pMediaTypeOut, MF_MT_FRAME_RATE, 30, 1);
  hr = MFSetAttributeSize(pMediaTypeOut, MF_MT_FRAME_SIZE, 720, 480);
  hr = MFSetAttributeRatio(pMediaTypeOut, MF_MT_PIXEL_ASPECT_RATIO, 16, 9);

  DWORD nWriterStreamIndex = -1;
  hr = MFCreateSinkWriterFromURL(L"./out.mp4", NULL, NULL, &pSinkWriter);
  hr = pSinkWriter->AddStream(pMediaTypeOut, &nWriterStreamIndex);
  hr = pSinkWriter->SetInputMediaType(nWriterStreamIndex, pPartialType, NULL);

  LONGLONG SampleDuration = 0L;
  hr = pSinkWriter->BeginWriting();

  for (;;)
  {
  DWORD nStreamIndex, nStreamFlags;
  LONGLONG nTime;
  IMFSample *pSample;

  hr = pSourceReader->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM,
  0,
  &nStreamIndex,
  &nStreamFlags,
  &nTime,
  &pSample);
  printf("FLAGS %d\n", nStreamFlags);
  printf("TIME %lld\n", nTime);

  if (nStreamFlags & MF_SOURCE_READERF_ENDOFSTREAM)
  {
  break;
  }

  //Update media type, when current media tye changed.
  if (nStreamFlags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED) {
  pSourceReader->GetNativeMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM, MF_SOURCE_READER_CURRENT_TYPE_INDEX, &pCurrentMediaType);
  printf("MediaType changed\n");
  pSourceReader->SetStreamSelection(MF_SOURCE_READER_FIRST_VIDEO_STREAM, TRUE);
  hr = pSinkWriter->SetInputMediaType(nWriterStreamIndex, pCurrentMediaType, NULL);
  continue;
  }
  pSample->GetSampleDuration(&SampleDuration);

  if (nTime >= nDruration)
  {
  break;
  }
  // Calculate new timestamp of sample when this sample is written on output file
  if (nTime + SampleDuration >= nDruration)
  {
  SampleDuration = nDruration - nTime;
  pSample->SetSampleDuration(SampleDuration);
  }
  pSample->SetSampleTime(nTime);

  if (FAILED(hr)) {
  printf("ReadSample Error...\n");
  return hr;
  }

  //write sample
  if (pSample)
  {
  OutputDebugString(L"Write sample...\n");
  hr = pSinkWriter->WriteSample(
  nWriterStreamIndex,
  pSample
  );
  if (FAILED(hr)) {
  pSample->Release();
  printf("WriteSample Error...\n");
  return hr;
  }
  pSample->Release();
  pSample = NULL;
  }
  }
  hr = pSinkWriter->Finalize();
  return 0;
 }

After running the program, I get the file "out.mp4". I play it with WMP (Window Media Player) and don't close it.

Then I run the program again, it crashes when calling MFCreateSinkWriterFromURL.

hr = HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION): The process cannot access the file because it is being used by another process.

I think the cause is out.mp4 being locked by WMP.
3. However, if I add a code to delete the out.mp4 file before calling MFCreateSinkWriterFromURL, the program will always run successfully. At this point, WMP will sometimes report an error.

 if (PathFileExistsW("./out.mp4")) {
  if (!DeleteFileW("./out.mp4")) {
  LERROR("msg", "delete output file failed", "error", GetLastError());
  }
 }

I try to delete a video file using File Explorer while the same file is still played by WMP. Results similar to step 3.

I did all the above steps again and replaced WMP with Movie&TV (on Win10), the results were slightly different.

In step 2, the program does not give error while the file is still playing on Movie&TV

In step 3 and step 4, we can always delete the file and Movie&TV gives error

0x8007002 - The item is missing or we can't get to it

So I have questions here:

  • With WMP, why can't we overwrite files (using Media Foundation) but we can delete files?
  • With Movie&TV, why can't the program detect the file being played by Movie&TV? Also like WMP, why can't the file be deleted while it's being played with Movie&TV ?
Windows API - Win32
Windows API - Win32
A core set of Windows application programming interfaces (APIs) for desktop and server applications. Previously known as Win32 API.
2,431 questions
{count} votes

1 answer

Sort by: Most helpful
  1. nthamy 6 Reputation points
    2021-10-12T10:09:59.133+00:00

    Hi @Xiaopo Yang - MSFT
    Thanks you for your support and sorry for the late response.

    I have tried running the MFCaptureToFile sample, however it doesn't solve the problem I have.
    Please notice my steps below:

    • Step 1: Run the program MFCaptureToFile.
    • Step 2: Start Capture.
    • Step 3: Open the output video file with WMP and let it opened when completed playing.
    • Step 4: Start Capture again to override the output file.
      => I get 0x80070020 error
    • Step 5: Close WMP window and override the file, I don't get the error.

    These phenomena are identical to the samle code I gave.
    I think the output file is locked by WMP so it won't be possible to overwrite the file without closing WMP or switching to another file.
    However I can delete the file even when WMP is playing the file. This is what I am most confused about. Please explain this problem.

    Also, if I use Movie&TV, I can not only delete the file, but also overwrite the date file while Movie&TV is playing the file.

    This is clearly the behavior of Window. Hopefully Microsoft has an update to fix this.