├── .gitignore
├── CONTRIBUTING.md
├── Doxyfile
├── LICENSE.md
├── README.md
├── examples
├── AnimationWriter
│ ├── .gitignore
│ ├── AnimationWriter.jucer
│ ├── Builds
│ │ ├── MacOSX
│ │ │ ├── AnimationWriter.xcodeproj
│ │ │ │ └── project.pbxproj
│ │ │ ├── Info-App.plist
│ │ │ └── RecentFilesMenuTemplate.nib
│ │ └── VisualStudio2015
│ │ │ ├── AnimationWriter - App.vcxproj
│ │ │ ├── AnimationWriter.sln
│ │ │ ├── AnimationWriter_App.vcxproj
│ │ │ ├── AnimationWriter_App.vcxproj.filters
│ │ │ └── resources.rc
│ └── Source
│ │ ├── Main.cpp
│ │ └── MainComponent.cpp
└── VideoPlayer
│ ├── .gitignore
│ ├── Builds
│ ├── MacOSX
│ │ ├── Info-App.plist
│ │ ├── RecentFilesMenuTemplate.nib
│ │ └── VideoPlayer.xcodeproj
│ │ │ └── project.pbxproj
│ └── VisualStudio2015
│ │ ├── VideoPlayer (App).vcxproj
│ │ ├── VideoPlayer - App.vcxproj
│ │ ├── VideoPlayer.sln
│ │ ├── VideoPlayer.vcxproj
│ │ ├── VideoPlayer.vcxproj.filters
│ │ ├── VideoPlayer_App.vcxproj
│ │ ├── VideoPlayer_App.vcxproj.filters
│ │ └── resources.rc
│ ├── Source
│ ├── Main.cpp
│ ├── MainComponent.cpp
│ └── OSDComponent.h
│ └── VideoPlayer.jucer
└── modules
├── filmstro_audiohelpers
├── filmstro_audiohelpers.h
├── filmstro_audiohelpers_AudioBufferFIFO.h
├── filmstro_audiohelpers_AudioProcessorPlayerSource.h
├── filmstro_audiohelpers_OutputSourcePlayer.h
└── filmstro_audiohelpers_SharedFormatManager.h
└── filmstro_ffmpeg
├── filmstro_ffmpeg.h
├── filmstro_ffmpeg_FFmpegVideoComponent.cpp
├── filmstro_ffmpeg_FFmpegVideoComponent.h
├── filmstro_ffmpeg_FFmpegVideoListener.h
├── filmstro_ffmpeg_FFmpegVideoReader.cpp
├── filmstro_ffmpeg_FFmpegVideoReader.h
├── filmstro_ffmpeg_FFmpegVideoScaler.h
├── filmstro_ffmpeg_FFmpegVideoWriter.cpp
└── filmstro_ffmpeg_FFmpegVideoWriter.h
/.gitignore:
--------------------------------------------------------------------------------
1 | docs/
2 | examples/VideoPlayer/Builds/VisualStudio2015/Win32/
3 | *.db
4 | *.opendb
5 | .DS_Store
6 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | filmstro_ffmpeg
2 | ===============
3 |
4 | This JUCE wrapper for the ffMpeg library was written by Daniel Walz (ffAudio),
5 | begun while working at Filmstro Ltd. in Brighton, UK.
6 |
7 | We welcome all contributions, suggestions and bug reports, as this is the strength of
8 | Open Source.
9 |
10 | However, we will decide at our discretion to accept or ignore pull requests.
11 | A pull request will not form any ownership of any of the code.
12 |
13 |
14 | Contributions so far:
15 |
16 | - Ian (ianatdolby): Added support for interleaved audio formats and use ffmpegs audio resampler
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | filmstro_ffmpeg - license
2 | =========================
3 |
4 | ```
5 | Copyright (c) 2017, Filmstro Ltd. - Daniel Walz
6 | All rights reserved.
7 |
8 | Redistribution and use in source and binary forms, with or without modification,
9 | are permitted provided that the following conditions are met:
10 | 1. Redistributions of source code must retain the above copyright notice, this
11 | list of conditions and the following disclaimer.
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 | 3. Neither the name of the copyright holder nor the names of its contributors
16 | may be used to endorse or promote products derived from this software without
17 | specific prior written permission.
18 |
19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28 | OF THE POSSIBILITY OF SUCH DAMAGE.
29 | ```
30 |
31 | Brighton, June 2017
32 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | filmstro_ffmpeg
3 | ===============
4 |
5 | by Daniel Walz / Filmstro Ltd.
6 | Published under the BSD License (3 clause)
7 |
8 | This is a module to read video files and play/display it using the JUCE
9 | framework (juce.com). The audio will be available as a juce::AudioSource and
10 | can be processed through a regular processing chain.
11 |
12 | Find the [API documentation here](https://filmstro.github.io/filmstro_ffmpeg/)
13 |
14 | Dependencies
15 | ============
16 |
17 | The reading is done using ffMpeg (ffmpeg.org). You will have to build ffmpeg
18 | and link your project to it, if it's not already installed. We use this flags:
19 |
20 | OSX:
21 |
22 | ./configure --cc=CC --arch=x86_64 --disable-static --enable-shared --disable-stripping --disable-debug --install-name-dir='@loader_path'
23 |
24 | Windows:
25 |
26 | ./configure --toolchain=msvc --disable-static --enable-shared --prefix=../build/windows --arch=x86
27 |
28 | To make
29 |
30 | make -j10
31 | make install
32 |
33 | You can add an audio meter simply by adding the module https://github.com/ffAudio/ff_meters to the projucer project.
34 |
35 |
36 | Current State
37 | =============
38 |
39 | It works for us with mp4 files. However, there are many formats that theoretically should work, but some create
40 | problems, probably to do with the sequence of packets / frames in the stream. To
41 | improve this any insights and findings are very welcome.
42 |
43 | There is an example how to write e.g. an Animation to a file, see examples/AnimationWriter. The animation is
44 | simply copied from the JUCE examples and the writer is added.
45 |
46 | ********************************************************************************
47 |
48 | We hope it is of any use, let us know of any problems or improvements you may
49 | come up with...
50 |
51 | Brighton, 9th February 2017
52 |
53 | ********************************************************************************
54 |
--------------------------------------------------------------------------------
/examples/AnimationWriter/.gitignore:
--------------------------------------------------------------------------------
1 | Builds/MacOSX/AnimationWriter.xcodeproj/xcuserdata/
2 | Builds/MacOSX/AnimationWriter.xcodeproj/project.xcworkspace/
3 | Builds/MacOSX/build/Debug/
4 | Builds/MacOSX/build/Release/
5 | Builds/MacOSX/build/AnimationWriter.build/
6 | JuceLibraryCode/
7 |
8 |
--------------------------------------------------------------------------------
/examples/AnimationWriter/AnimationWriter.jucer:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
11 |
12 |
13 |
14 |
15 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
43 |
44 |
46 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/examples/AnimationWriter/Builds/MacOSX/AnimationWriter.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | 84126614E38094C3A6753F77 = {isa = PBXBuildFile; fileRef = 8DF8A1F530B4D5B24DB2131C; };
10 | CE615F8434ABFDB021B30FFB = {isa = PBXBuildFile; fileRef = CFB3210F0790D39592202590; };
11 | 593329D60E6758C4146C518C = {isa = PBXBuildFile; fileRef = 662BA9AE35EC1C3CACE89D0F; };
12 | 48E26FFCF88747E719A998D3 = {isa = PBXBuildFile; fileRef = 279D2FC78D87D6F7C2A5FB6F; };
13 | C05FDDE9AC9700481D429AA9 = {isa = PBXBuildFile; fileRef = 1CA0B5B547A04CBEDC73EA29; };
14 | 77B10A2FC144AE8105F3E3CC = {isa = PBXBuildFile; fileRef = 2B017EBADD3C1142DC5B4583; };
15 | 90FFC256DA2692235C34AC47 = {isa = PBXBuildFile; fileRef = 9E0769B33582C0556942253C; };
16 | 2C84E713BD4E8A790B6FB7D0 = {isa = PBXBuildFile; fileRef = 97BF18FDF6295096BAFF514A; };
17 | 2AAB862BBA1269374C8CBF37 = {isa = PBXBuildFile; fileRef = D56051ED1536EE645AF154C4; };
18 | 383EB94E9E953681C7AFE5BE = {isa = PBXBuildFile; fileRef = 30C0A0262206EA700AAE1FC1; };
19 | B6354D10CFCB76715D00518B = {isa = PBXBuildFile; fileRef = 3E9B3AB19191B41F738629F3; };
20 | AB3CF6D773A815C9F590561A = {isa = PBXBuildFile; fileRef = BE4E0356AA8265B8866DB6A2; };
21 | E6E13134807C2B30FC82E9CC = {isa = PBXBuildFile; fileRef = A74DAC0C8D5107ABF6AAEF2D; };
22 | 1DA2ACDDC4DA4D016015ED11 = {isa = PBXBuildFile; fileRef = AED04C702F5B55957D5C445F; };
23 | 35913D20399BA1526162387C = {isa = PBXBuildFile; fileRef = 0CD2392379DE0F9F87A0107E; };
24 | 2B01C40B1DBA960DB3A55B66 = {isa = PBXBuildFile; fileRef = 607CE387A481957CDD59D90E; };
25 | 74E55A83A5367F9ED189BC1F = {isa = PBXBuildFile; fileRef = 7D47134AB08DF97F9DA79300; };
26 | A8F0A4402B93EF710C262E32 = {isa = PBXBuildFile; fileRef = D9FCEBF3117A0F32EAC498D4; };
27 | 0BD92437D8A2325D5F38D88C = {isa = PBXBuildFile; fileRef = B81BF1239BCF78413757DC1C; };
28 | D0E4A6DDEB4FA8ACFAAC9196 = {isa = PBXBuildFile; fileRef = 52B267CE2126115014DA1748; };
29 | CF4B2BDF07BEAD43D3C74000 = {isa = PBXBuildFile; fileRef = FE8AE66E95BB7A2A89FB2302; };
30 | 86215578F641BD4CD768B944 = {isa = PBXBuildFile; fileRef = 3BCCEDFD2C3A07C096624889; };
31 | 8513F4FA617B7FAA2A417744 = {isa = PBXBuildFile; fileRef = 1EBA5D3E157DDDDA5B423EF4; };
32 | 699ECA9670F19F9DED971A6B = {isa = PBXBuildFile; fileRef = 2DD60BD7849677BF1AF4BC18; };
33 | 0774292A8A728CFB5C6EBE7B = {isa = PBXBuildFile; fileRef = 89D541C1C81041585FB7F620; };
34 | 0DF9E6ABDC25C19DEA206B1B = {isa = PBXBuildFile; fileRef = 3D8C99E65316150252498CC8; };
35 | 11DE783EFABFD48CCDC4F4BB = {isa = PBXBuildFile; fileRef = B05227A3BD24ACFAE688B147; };
36 | 9F82D1B651088851DF81A384 = {isa = PBXBuildFile; fileRef = CA32A431DE2B3AB5B4BBA6D7; };
37 | F44A81EEE6FC217D134DBB90 = {isa = PBXBuildFile; fileRef = 9D7082639AE07EFC4448FD63; };
38 | 7EBB9EB20F6A6EB1E07A2BA1 = {isa = PBXBuildFile; fileRef = 07C37447DC474934AA6113D0; };
39 | 930E5950447B5A2245709B21 = {isa = PBXBuildFile; fileRef = 66280D8E82D2DD905497DB4B; };
40 | 7CD5E6EE983829CD82BC5FFE = {isa = PBXBuildFile; fileRef = A905989DD8CE5F62C0C3E373; };
41 | 07C37447DC474934AA6113D0 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_gui_extra.mm"; path = "../../JuceLibraryCode/include_juce_gui_extra.mm"; sourceTree = "SOURCE_ROOT"; };
42 | 0CD2392379DE0F9F87A0107E = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = MainComponent.cpp; path = ../../Source/MainComponent.cpp; sourceTree = "SOURCE_ROOT"; };
43 | 1CA0B5B547A04CBEDC73EA29 = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; };
44 | 1EBA5D3E157DDDDA5B423EF4 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_audio_processors.mm"; path = "../../JuceLibraryCode/include_juce_audio_processors.mm"; sourceTree = "SOURCE_ROOT"; };
45 | 237FDBE0A0B24D510E72F1FD = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_gui_basics"; path = "$(HOME)/Developer/JUCE5/modules/juce_gui_basics"; sourceTree = ""; };
46 | 279D2FC78D87D6F7C2A5FB6F = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };
47 | 2B017EBADD3C1142DC5B4583 = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
48 | 2DD60BD7849677BF1AF4BC18 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_core.mm"; path = "../../JuceLibraryCode/include_juce_core.mm"; sourceTree = "SOURCE_ROOT"; };
49 | 30C0A0262206EA700AAE1FC1 = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; };
50 | 3BCCEDFD2C3A07C096624889 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_audio_formats.mm"; path = "../../JuceLibraryCode/include_juce_audio_formats.mm"; sourceTree = "SOURCE_ROOT"; };
51 | 3D8C99E65316150252498CC8 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_data_structures.mm"; path = "../../JuceLibraryCode/include_juce_data_structures.mm"; sourceTree = "SOURCE_ROOT"; };
52 | 3E9B3AB19191B41F738629F3 = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
53 | 438284FE3877E1977AF27441 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_opengl"; path = "$(HOME)/Developer/JUCE5/modules/juce_opengl"; sourceTree = ""; };
54 | 52B267CE2126115014DA1748 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_audio_basics.mm"; path = "../../JuceLibraryCode/include_juce_audio_basics.mm"; sourceTree = "SOURCE_ROOT"; };
55 | 52E88916F57D26B99A94EC2B = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AppConfig.h; path = ../../JuceLibraryCode/AppConfig.h; sourceTree = "SOURCE_ROOT"; };
56 | 607CE387A481957CDD59D90E = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Main.cpp; path = ../../Source/Main.cpp; sourceTree = "SOURCE_ROOT"; };
57 | 66280D8E82D2DD905497DB4B = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_opengl.mm"; path = "../../JuceLibraryCode/include_juce_opengl.mm"; sourceTree = "SOURCE_ROOT"; };
58 | 662BA9AE35EC1C3CACE89D0F = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
59 | 6EC2D41E236228B2D0F1C127 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_audio_processors"; path = "$(HOME)/Developer/JUCE5/modules/juce_audio_processors"; sourceTree = ""; };
60 | 72BB758EA230626FC98EDD2B = {isa = PBXFileReference; lastKnownFileType = file; name = "filmstro_audiohelpers"; path = "../../../../modules/filmstro_audiohelpers"; sourceTree = "SOURCE_ROOT"; };
61 | 7D47134AB08DF97F9DA79300 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "include_filmstro_ffmpeg_FFmpegVideoComponent.cpp"; path = "../../JuceLibraryCode/include_filmstro_ffmpeg_FFmpegVideoComponent.cpp"; sourceTree = "SOURCE_ROOT"; };
62 | 7EA266B152B5E71634EE7E90 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_events"; path = "$(HOME)/Developer/JUCE5/modules/juce_events"; sourceTree = ""; };
63 | 87AA51F8ABC360ED4BE5A3D5 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_audio_basics"; path = "$(HOME)/Developer/JUCE5/modules/juce_audio_basics"; sourceTree = ""; };
64 | 883ADA1A8E18370962E49FCD = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_data_structures"; path = "$(HOME)/Developer/JUCE5/modules/juce_data_structures"; sourceTree = ""; };
65 | 89D541C1C81041585FB7F620 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_cryptography.mm"; path = "../../JuceLibraryCode/include_juce_cryptography.mm"; sourceTree = "SOURCE_ROOT"; };
66 | 8B684384CABF6CA6E885CF81 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = JuceHeader.h; path = ../../JuceLibraryCode/JuceHeader.h; sourceTree = "SOURCE_ROOT"; };
67 | 8DF8A1F530B4D5B24DB2131C = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AnimationWriter.app; sourceTree = "BUILT_PRODUCTS_DIR"; };
68 | 97BF18FDF6295096BAFF514A = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; };
69 | 9D7082639AE07EFC4448FD63 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_gui_basics.mm"; path = "../../JuceLibraryCode/include_juce_gui_basics.mm"; sourceTree = "SOURCE_ROOT"; };
70 | 9E0769B33582C0556942253C = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = System/Library/Frameworks/CoreAudio.framework; sourceTree = SDKROOT; };
71 | A283AB3BA5E5BB13A672D29F = {isa = PBXFileReference; lastKnownFileType = file; name = "filmstro_ffmpeg"; path = "../../../../modules/filmstro_ffmpeg"; sourceTree = "SOURCE_ROOT"; };
72 | A59C895A18329C62AD9A039B = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_cryptography"; path = "$(HOME)/Developer/JUCE5/modules/juce_cryptography"; sourceTree = ""; };
73 | A74DAC0C8D5107ABF6AAEF2D = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; };
74 | A905989DD8CE5F62C0C3E373 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_video.mm"; path = "../../JuceLibraryCode/include_juce_video.mm"; sourceTree = "SOURCE_ROOT"; };
75 | AED04C702F5B55957D5C445F = {isa = PBXFileReference; lastKnownFileType = file.nib; name = RecentFilesMenuTemplate.nib; path = RecentFilesMenuTemplate.nib; sourceTree = "SOURCE_ROOT"; };
76 | B05227A3BD24ACFAE688B147 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_events.mm"; path = "../../JuceLibraryCode/include_juce_events.mm"; sourceTree = "SOURCE_ROOT"; };
77 | B13037D3D34D3E0805769B4F = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_graphics"; path = "$(HOME)/Developer/JUCE5/modules/juce_graphics"; sourceTree = ""; };
78 | B5497809C3BE72F221C205AB = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "Info-App.plist"; path = "Info-App.plist"; sourceTree = "SOURCE_ROOT"; };
79 | B73FD37DB7C051B88D354E30 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_core"; path = "$(HOME)/Developer/JUCE5/modules/juce_core"; sourceTree = ""; };
80 | B81BF1239BCF78413757DC1C = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "include_filmstro_ffmpeg_FFmpegVideoWriter.cpp"; path = "../../JuceLibraryCode/include_filmstro_ffmpeg_FFmpegVideoWriter.cpp"; sourceTree = "SOURCE_ROOT"; };
81 | B96262CDB7EC68FB4A7B15C1 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_audio_devices"; path = "$(HOME)/Developer/JUCE5/modules/juce_audio_devices"; sourceTree = ""; };
82 | BE4E0356AA8265B8866DB6A2 = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
83 | CA32A431DE2B3AB5B4BBA6D7 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_graphics.mm"; path = "../../JuceLibraryCode/include_juce_graphics.mm"; sourceTree = "SOURCE_ROOT"; };
84 | CFB3210F0790D39592202590 = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; };
85 | D56051ED1536EE645AF154C4 = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMIDI.framework; path = System/Library/Frameworks/CoreMIDI.framework; sourceTree = SDKROOT; };
86 | D9FCEBF3117A0F32EAC498D4 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "include_filmstro_ffmpeg_FFmpegVideoReader.cpp"; path = "../../JuceLibraryCode/include_filmstro_ffmpeg_FFmpegVideoReader.cpp"; sourceTree = "SOURCE_ROOT"; };
87 | DE0D306E8BA00467337E9D82 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_video"; path = "$(HOME)/Developer/JUCE5/modules/juce_video"; sourceTree = ""; };
88 | DF6B2F765E7761DB1C5DC083 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_gui_extra"; path = "$(HOME)/Developer/JUCE5/modules/juce_gui_extra"; sourceTree = ""; };
89 | FDEAA1C503C7808DD969B2A4 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_audio_formats"; path = "$(HOME)/Developer/JUCE5/modules/juce_audio_formats"; sourceTree = ""; };
90 | FE8AE66E95BB7A2A89FB2302 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_audio_devices.mm"; path = "../../JuceLibraryCode/include_juce_audio_devices.mm"; sourceTree = "SOURCE_ROOT"; };
91 | 945A878486F49E9C89244D90 = {isa = PBXGroup; children = (
92 | 0CD2392379DE0F9F87A0107E,
93 | 607CE387A481957CDD59D90E, ); name = Source; sourceTree = ""; };
94 | 78F0CD72045EA38F6D2A47A6 = {isa = PBXGroup; children = (
95 | 945A878486F49E9C89244D90, ); name = AnimationWriter; sourceTree = ""; };
96 | 6ED9A120F41C32CDFA5A6700 = {isa = PBXGroup; children = (
97 | 72BB758EA230626FC98EDD2B,
98 | A283AB3BA5E5BB13A672D29F,
99 | 87AA51F8ABC360ED4BE5A3D5,
100 | B96262CDB7EC68FB4A7B15C1,
101 | FDEAA1C503C7808DD969B2A4,
102 | 6EC2D41E236228B2D0F1C127,
103 | B73FD37DB7C051B88D354E30,
104 | A59C895A18329C62AD9A039B,
105 | 883ADA1A8E18370962E49FCD,
106 | 7EA266B152B5E71634EE7E90,
107 | B13037D3D34D3E0805769B4F,
108 | 237FDBE0A0B24D510E72F1FD,
109 | DF6B2F765E7761DB1C5DC083,
110 | 438284FE3877E1977AF27441,
111 | DE0D306E8BA00467337E9D82, ); name = "Juce Modules"; sourceTree = ""; };
112 | 41C5DD571C74F64C5CA70811 = {isa = PBXGroup; children = (
113 | 52E88916F57D26B99A94EC2B,
114 | 7D47134AB08DF97F9DA79300,
115 | D9FCEBF3117A0F32EAC498D4,
116 | B81BF1239BCF78413757DC1C,
117 | 52B267CE2126115014DA1748,
118 | FE8AE66E95BB7A2A89FB2302,
119 | 3BCCEDFD2C3A07C096624889,
120 | 1EBA5D3E157DDDDA5B423EF4,
121 | 2DD60BD7849677BF1AF4BC18,
122 | 89D541C1C81041585FB7F620,
123 | 3D8C99E65316150252498CC8,
124 | B05227A3BD24ACFAE688B147,
125 | CA32A431DE2B3AB5B4BBA6D7,
126 | 9D7082639AE07EFC4448FD63,
127 | 07C37447DC474934AA6113D0,
128 | 66280D8E82D2DD905497DB4B,
129 | A905989DD8CE5F62C0C3E373,
130 | 8B684384CABF6CA6E885CF81, ); name = "Juce Library Code"; sourceTree = ""; };
131 | D8669A6265CA1F15C34E3164 = {isa = PBXGroup; children = (
132 | B5497809C3BE72F221C205AB,
133 | AED04C702F5B55957D5C445F, ); name = Resources; sourceTree = ""; };
134 | 02EA7C7CB17F53C195545442 = {isa = PBXGroup; children = (
135 | CFB3210F0790D39592202590,
136 | 662BA9AE35EC1C3CACE89D0F,
137 | 279D2FC78D87D6F7C2A5FB6F,
138 | 1CA0B5B547A04CBEDC73EA29,
139 | 2B017EBADD3C1142DC5B4583,
140 | 9E0769B33582C0556942253C,
141 | 97BF18FDF6295096BAFF514A,
142 | D56051ED1536EE645AF154C4,
143 | 30C0A0262206EA700AAE1FC1,
144 | 3E9B3AB19191B41F738629F3,
145 | BE4E0356AA8265B8866DB6A2,
146 | A74DAC0C8D5107ABF6AAEF2D, ); name = Frameworks; sourceTree = ""; };
147 | 8BFE04FF8097C999BF6B1964 = {isa = PBXGroup; children = (
148 | 8DF8A1F530B4D5B24DB2131C, ); name = Products; sourceTree = ""; };
149 | 31511396049F550DED41F41D = {isa = PBXGroup; children = (
150 | 78F0CD72045EA38F6D2A47A6,
151 | 6ED9A120F41C32CDFA5A6700,
152 | 41C5DD571C74F64C5CA70811,
153 | D8669A6265CA1F15C34E3164,
154 | 02EA7C7CB17F53C195545442,
155 | 8BFE04FF8097C999BF6B1964, ); name = Source; sourceTree = ""; };
156 | 066983D19FEF06B6D9D88FA9 = {isa = XCBuildConfiguration; buildSettings = {
157 | CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
158 | CLANG_LINK_OBJC_RUNTIME = NO;
159 | COMBINE_HIDPI_IMAGES = YES;
160 | CONFIGURATION_BUILD_DIR = "$(PROJECT_DIR)/build/$(CONFIGURATION)";
161 | COPY_PHASE_STRIP = NO;
162 | GCC_DYNAMIC_NO_PIC = NO;
163 | GCC_OPTIMIZATION_LEVEL = 0;
164 | GCC_PREPROCESSOR_DEFINITIONS = (
165 | "_DEBUG=1",
166 | "DEBUG=1",
167 | "FFMPEG_ROOT=/usr/local",
168 | "JUCER_XCODE_MAC_F6D2F4CF=1",
169 | "JUCE_APP_VERSION=1.0.0",
170 | "JUCE_APP_VERSION_HEX=0x10000",
171 | "JucePlugin_Build_VST=0",
172 | "JucePlugin_Build_VST3=0",
173 | "JucePlugin_Build_AU=0",
174 | "JucePlugin_Build_AUv3=0",
175 | "JucePlugin_Build_RTAS=0",
176 | "JucePlugin_Build_AAX=0",
177 | "JucePlugin_Build_Standalone=0", );
178 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
179 | HEADER_SEARCH_PATHS = ("../../JuceLibraryCode", "../../../../modules", "~/Developer/JUCE5/modules", "$(inherited)");
180 | INFOPLIST_FILE = Info-App.plist;
181 | INFOPLIST_PREPROCESS = NO;
182 | INSTALL_PATH = "$(HOME)/Applications";
183 | MACOSX_DEPLOYMENT_TARGET = 10.11;
184 | MACOSX_DEPLOYMENT_TARGET_ppc = 10.4;
185 | OTHER_CPLUSPLUSFLAGS = "-Wno-reserved-user-defined-literal -I/usr/local/include";
186 | OTHER_LDFLAGS = "-L/usr/local/lib -lavformat -lavutil -lavcodec -lswscale -lswresample";
187 | PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.AnimationWriter;
188 | SDKROOT_ppc = macosx10.5;
189 | USE_HEADERMAP = NO; }; name = Debug; };
190 | F99DD5D54406C943444B6911 = {isa = XCBuildConfiguration; buildSettings = {
191 | CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
192 | CLANG_LINK_OBJC_RUNTIME = NO;
193 | COMBINE_HIDPI_IMAGES = YES;
194 | CONFIGURATION_BUILD_DIR = "$(PROJECT_DIR)/build/$(CONFIGURATION)";
195 | DEAD_CODE_STRIPPING = YES;
196 | GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
197 | GCC_OPTIMIZATION_LEVEL = 3;
198 | GCC_PREPROCESSOR_DEFINITIONS = (
199 | "_NDEBUG=1",
200 | "NDEBUG=1",
201 | "FFMPEG_ROOT=/usr/local",
202 | "JUCER_XCODE_MAC_F6D2F4CF=1",
203 | "JUCE_APP_VERSION=1.0.0",
204 | "JUCE_APP_VERSION_HEX=0x10000",
205 | "JucePlugin_Build_VST=0",
206 | "JucePlugin_Build_VST3=0",
207 | "JucePlugin_Build_AU=0",
208 | "JucePlugin_Build_AUv3=0",
209 | "JucePlugin_Build_RTAS=0",
210 | "JucePlugin_Build_AAX=0",
211 | "JucePlugin_Build_Standalone=0", );
212 | GCC_SYMBOLS_PRIVATE_EXTERN = YES;
213 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
214 | HEADER_SEARCH_PATHS = ("../../JuceLibraryCode", "../../../../modules", "~/Developer/JUCE5/modules", "$(inherited)");
215 | INFOPLIST_FILE = Info-App.plist;
216 | INFOPLIST_PREPROCESS = NO;
217 | INSTALL_PATH = "$(HOME)/Applications";
218 | MACOSX_DEPLOYMENT_TARGET = 10.11;
219 | MACOSX_DEPLOYMENT_TARGET_ppc = 10.4;
220 | OTHER_CPLUSPLUSFLAGS = "-Wno-reserved-user-defined-literal -I/usr/local/include";
221 | OTHER_LDFLAGS = "-L/usr/local/lib -lavformat -lavutil -lavcodec -lswscale -lswresample";
222 | PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.AnimationWriter;
223 | SDKROOT_ppc = macosx10.5;
224 | USE_HEADERMAP = NO; }; name = Release; };
225 | F9941B8D7DFDAB3B819AB248 = {isa = XCBuildConfiguration; buildSettings = {
226 | ALWAYS_SEARCH_USER_PATHS = NO;
227 | DEBUG_INFORMATION_FORMAT = "dwarf";
228 | ENABLE_TESTABILITY = YES;
229 | GCC_C_LANGUAGE_STANDARD = c11;
230 | GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
231 | GCC_MODEL_TUNING = G5;
232 | GCC_WARN_ABOUT_RETURN_TYPE = YES;
233 | GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
234 | GCC_WARN_MISSING_PARENTHESES = YES;
235 | GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
236 | GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
237 | GCC_WARN_UNUSED_VARIABLE = YES;
238 | ONLY_ACTIVE_ARCH = YES;
239 | PRODUCT_NAME = "AnimationWriter";
240 | WARNING_CFLAGS = -Wreorder;
241 | ZERO_LINK = NO; }; name = Debug; };
242 | 460AD3503A3223BEF2698BE2 = {isa = XCBuildConfiguration; buildSettings = {
243 | ALWAYS_SEARCH_USER_PATHS = NO;
244 | DEBUG_INFORMATION_FORMAT = "dwarf";
245 | GCC_C_LANGUAGE_STANDARD = c11;
246 | GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
247 | GCC_MODEL_TUNING = G5;
248 | GCC_WARN_ABOUT_RETURN_TYPE = YES;
249 | GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
250 | GCC_WARN_MISSING_PARENTHESES = YES;
251 | GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
252 | GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
253 | GCC_WARN_UNUSED_VARIABLE = YES;
254 | PRODUCT_NAME = "AnimationWriter";
255 | WARNING_CFLAGS = -Wreorder;
256 | ZERO_LINK = NO; }; name = Release; };
257 | 5E8742E6ADED0EC90F6C38AA = {isa = PBXTargetDependency; target = 5D6BC08B04394F552E02BFF9; };
258 | 94EAD700A7D3033D1BFEDAF0 = {isa = XCConfigurationList; buildConfigurations = (
259 | F9941B8D7DFDAB3B819AB248,
260 | 460AD3503A3223BEF2698BE2, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; };
261 | 56F62D5302E537E6E8679767 = {isa = XCConfigurationList; buildConfigurations = (
262 | 066983D19FEF06B6D9D88FA9,
263 | F99DD5D54406C943444B6911, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; };
264 | 0FF969CA22DF317AC1372AE5 = {isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = (
265 | 1DA2ACDDC4DA4D016015ED11, ); runOnlyForDeploymentPostprocessing = 0; };
266 | C0373C521259D11A862870DC = {isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = (
267 | 35913D20399BA1526162387C,
268 | 2B01C40B1DBA960DB3A55B66,
269 | 74E55A83A5367F9ED189BC1F,
270 | A8F0A4402B93EF710C262E32,
271 | 0BD92437D8A2325D5F38D88C,
272 | D0E4A6DDEB4FA8ACFAAC9196,
273 | CF4B2BDF07BEAD43D3C74000,
274 | 86215578F641BD4CD768B944,
275 | 8513F4FA617B7FAA2A417744,
276 | 699ECA9670F19F9DED971A6B,
277 | 0774292A8A728CFB5C6EBE7B,
278 | 0DF9E6ABDC25C19DEA206B1B,
279 | 11DE783EFABFD48CCDC4F4BB,
280 | 9F82D1B651088851DF81A384,
281 | F44A81EEE6FC217D134DBB90,
282 | 7EBB9EB20F6A6EB1E07A2BA1,
283 | 930E5950447B5A2245709B21,
284 | 7CD5E6EE983829CD82BC5FFE, ); runOnlyForDeploymentPostprocessing = 0; };
285 | 7226A6A93265F6BC225430EF = {isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = (
286 | CE615F8434ABFDB021B30FFB,
287 | 593329D60E6758C4146C518C,
288 | 48E26FFCF88747E719A998D3,
289 | C05FDDE9AC9700481D429AA9,
290 | 77B10A2FC144AE8105F3E3CC,
291 | 90FFC256DA2692235C34AC47,
292 | 2C84E713BD4E8A790B6FB7D0,
293 | 2AAB862BBA1269374C8CBF37,
294 | 383EB94E9E953681C7AFE5BE,
295 | B6354D10CFCB76715D00518B,
296 | AB3CF6D773A815C9F590561A,
297 | E6E13134807C2B30FC82E9CC, ); runOnlyForDeploymentPostprocessing = 0; };
298 | 5D6BC08B04394F552E02BFF9 = {isa = PBXNativeTarget; buildConfigurationList = 56F62D5302E537E6E8679767; buildPhases = (
299 | 0FF969CA22DF317AC1372AE5,
300 | C0373C521259D11A862870DC,
301 | 7226A6A93265F6BC225430EF, ); buildRules = ( ); dependencies = ( ); name = "AnimationWriter - App"; productName = AnimationWriter; productReference = 8DF8A1F530B4D5B24DB2131C; productType = "com.apple.product-type.application"; };
302 | 8B6A3CB88895A77F238B08B6 = {isa = PBXProject; buildConfigurationList = 94EAD700A7D3033D1BFEDAF0; attributes = { LastUpgradeCheck = 0830; TargetAttributes = { 5D6BC08B04394F552E02BFF9 = { SystemCapabilities = {com.apple.InAppPurchase = { enabled = 0; }; com.apple.InterAppAudio = { enabled = 0; }; com.apple.Sandbox = { enabled = 0; }; }; }; }; }; compatibilityVersion = "Xcode 3.2"; hasScannedForEncodings = 0; mainGroup = 31511396049F550DED41F41D; projectDirPath = ""; projectRoot = ""; targets = (5D6BC08B04394F552E02BFF9); };
303 | };
304 | rootObject = 8B6A3CB88895A77F238B08B6;
305 | }
306 |
--------------------------------------------------------------------------------
/examples/AnimationWriter/Builds/MacOSX/Info-App.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | CFBundleExecutable
7 | ${EXECUTABLE_NAME}
8 | CFBundleIconFile
9 |
10 | CFBundleIdentifier
11 | $(PRODUCT_BUNDLE_IDENTIFIER)
12 | CFBundleName
13 | AnimationWriter
14 | CFBundleDisplayName
15 | AnimationWriter
16 | CFBundlePackageType
17 | APPL
18 | CFBundleSignature
19 | ????
20 | CFBundleShortVersionString
21 | 1.0.0
22 | CFBundleVersion
23 | 1.0.0
24 | NSHumanReadableCopyright
25 |
26 | NSHighResolutionCapable
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/examples/AnimationWriter/Builds/MacOSX/RecentFilesMenuTemplate.nib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/filmstro/filmstro_ffmpeg/ebb79f7713742311d09ac3f2215d807e88e3a517/examples/AnimationWriter/Builds/MacOSX/RecentFilesMenuTemplate.nib
--------------------------------------------------------------------------------
/examples/AnimationWriter/Builds/VisualStudio2015/AnimationWriter - App.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 | Debug
9 | x64
10 |
11 |
12 | Release
13 | x64
14 |
15 |
16 |
17 | {91D32CDA-AB1B-359D-8A4D-F196B0B23693}
18 | v140
19 |
20 |
21 |
23 | Application
24 | false
25 | v140
26 | v140
27 |
28 |
30 | Application
31 | false
32 | true
33 | v140
34 | v140
35 |
36 |
37 |
38 |
39 |
42 |
43 |
44 | v140
45 |
46 |
47 | <_ProjectFileVersion>10.0.30319.1
48 | .exe
49 | $(SolutionDir)\$(Platform)\$(Configuration)\App\
50 | $(Platform)\$(Configuration)\App\
51 | AnimationWriter
52 | true
53 | $(SolutionDir)\$(Platform)\$(Configuration)\App\
54 | $(Platform)\$(Configuration)\App\
55 | AnimationWriter
56 | true
57 | v140
58 |
59 |
60 |
61 | _DEBUG;%(PreprocessorDefinitions)
62 | true
63 | true
64 | Win32
65 |
66 |
67 |
68 | Disabled
69 | ProgramDatabase
70 | ..\..\JuceLibraryCode;..\..\..\..\modules;..\..\..\..\..\..\..\JUCE\modules;%(AdditionalIncludeDirectories)
71 | _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2015_78A5022=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;%(PreprocessorDefinitions)
72 | MultiThreadedDebug
73 | true
74 |
75 | $(IntDir)\
76 | $(IntDir)\
77 | $(IntDir)\
78 | Level4
79 | true
80 | true
81 | -I../../../../../../FFmpeg/build/windows/include %(AdditionalOptions)
82 |
83 |
84 | _DEBUG;%(PreprocessorDefinitions)
85 |
86 |
87 | $(OutDir)\AnimationWriter.exe
88 | true
89 | libcmt.lib; msvcrt.lib;;%(IgnoreSpecificDefaultLibraries)
90 | true
91 | $(IntDir)\AnimationWriter.pdb
92 | Windows
93 | true
94 | avformat.lib;avutil.lib;avcodec.lib;swscale.lib;swresample.lib;%(AdditionalDependencies)
95 | -LIBPATH:../../../../../../FFmpeg/build/windows/bin %(AdditionalOptions)
96 |
97 |
98 | true
99 | $(IntDir)\AnimationWriter.bsc
100 |
101 |
102 |
103 |
104 | NDEBUG;%(PreprocessorDefinitions)
105 | true
106 | true
107 | Win32
108 |
109 |
110 |
111 | Full
112 | ..\..\JuceLibraryCode;..\..\..\..\modules;..\..\..\..\..\..\..\JUCE\modules;%(AdditionalIncludeDirectories)
113 | _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2015_78A5022=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;%(PreprocessorDefinitions)
114 | MultiThreaded
115 | true
116 |
117 | $(IntDir)\
118 | $(IntDir)\
119 | $(IntDir)\
120 | Level4
121 | true
122 | true
123 | -I../../../../../../FFmpeg/build/windows/include %(AdditionalOptions)
124 |
125 |
126 | NDEBUG;%(PreprocessorDefinitions)
127 |
128 |
129 | $(OutDir)\AnimationWriter.exe
130 | true
131 | %(IgnoreSpecificDefaultLibraries)
132 | false
133 | $(IntDir)\AnimationWriter.pdb
134 | Windows
135 | true
136 | true
137 | true
138 | avformat.lib;avutil.lib;avcodec.lib;swscale.lib;swresample.lib;%(AdditionalDependencies)
139 | -LIBPATH:../../../../../../FFmpeg/build/windows/bin %(AdditionalOptions)
140 |
141 |
142 | true
143 | $(IntDir)\AnimationWriter.bsc
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
--------------------------------------------------------------------------------
/examples/AnimationWriter/Builds/VisualStudio2015/AnimationWriter.sln:
--------------------------------------------------------------------------------
1 | Microsoft Visual Studio Solution File, Format Version 11.00
2 | # Visual Studio 2015
3 |
4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AnimationWriter - App", "AnimationWriter_App.vcxproj", "{91D32CDA-AB1B-359D-8A4D-F196B0B23693}"
5 | EndProject
6 | Global
7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
8 | Debug|x64 = Debug|x64
9 | Release|x64 = Release|x64
10 | EndGlobalSection
11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
12 | {91D32CDA-AB1B-359D-8A4D-F196B0B23693}.Debug|x64.Build.0 = Debug|x64
13 | {91D32CDA-AB1B-359D-8A4D-F196B0B23693}.Debug|x64.ActiveCfg = Debug|x64
14 | {91D32CDA-AB1B-359D-8A4D-F196B0B23693}.Release|x64.Build.0 = Release|x64
15 | {91D32CDA-AB1B-359D-8A4D-F196B0B23693}.Release|x64.ActiveCfg = Release|x64
16 | EndGlobalSection
17 | GlobalSection(SolutionProperties) = preSolution
18 | HideSolutionNode = FALSE
19 | EndGlobalSection
20 | EndGlobal
21 |
--------------------------------------------------------------------------------
/examples/AnimationWriter/Builds/VisualStudio2015/resources.rc:
--------------------------------------------------------------------------------
1 | #ifdef JUCE_USER_DEFINED_RC_FILE
2 | #include JUCE_USER_DEFINED_RC_FILE
3 | #else
4 |
5 | #undef WIN32_LEAN_AND_MEAN
6 | #define WIN32_LEAN_AND_MEAN
7 | #include
8 |
9 | VS_VERSION_INFO VERSIONINFO
10 | FILEVERSION 1,0,0,0
11 | BEGIN
12 | BLOCK "StringFileInfo"
13 | BEGIN
14 | BLOCK "040904E4"
15 | BEGIN
16 | VALUE "FileDescription", "AnimationWriter\0"
17 | VALUE "FileVersion", "1.0.0\0"
18 | VALUE "ProductName", "AnimationWriter\0"
19 | VALUE "ProductVersion", "1.0.0\0"
20 | END
21 | END
22 |
23 | BLOCK "VarFileInfo"
24 | BEGIN
25 | VALUE "Translation", 0x409, 1252
26 | END
27 | END
28 |
29 | #endif
30 |
--------------------------------------------------------------------------------
/examples/AnimationWriter/Source/Main.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 |
4 | This file was auto-generated!
5 |
6 | It contains the basic startup code for a Juce application.
7 |
8 | ==============================================================================
9 | */
10 |
11 | #include "../JuceLibraryCode/JuceHeader.h"
12 |
13 | Component* createMainContentComponent();
14 |
15 | //==============================================================================
16 | class AnimationWriterApplication : public JUCEApplication
17 | {
18 | public:
19 | //==============================================================================
20 | AnimationWriterApplication() {}
21 |
22 | const String getApplicationName() override { return ProjectInfo::projectName; }
23 | const String getApplicationVersion() override { return ProjectInfo::versionString; }
24 | bool moreThanOneInstanceAllowed() override { return true; }
25 |
26 | //==============================================================================
27 | void initialise (const String& commandLine) override
28 | {
29 | // This method is where you should put your application's initialisation code..
30 |
31 | mainWindow = new MainWindow (getApplicationName());
32 | }
33 |
34 | void shutdown() override
35 | {
36 | // Add your application's shutdown code here..
37 |
38 | mainWindow = nullptr; // (deletes our window)
39 | }
40 |
41 | //==============================================================================
42 | void systemRequestedQuit() override
43 | {
44 | // This is called when the app is being asked to quit: you can ignore this
45 | // request and let the app carry on running, or call quit() to allow the app to close.
46 | quit();
47 | }
48 |
49 | void anotherInstanceStarted (const String& commandLine) override
50 | {
51 | // When another instance of the app is launched while this one is running,
52 | // this method is invoked, and the commandLine parameter tells you what
53 | // the other instance's command-line arguments were.
54 | }
55 |
56 | //==============================================================================
57 | /*
58 | This class implements the desktop window that contains an instance of
59 | our MainContentComponent class.
60 | */
61 | class MainWindow : public DocumentWindow
62 | {
63 | public:
64 | MainWindow (String name) : DocumentWindow (name,
65 | Desktop::getInstance().getDefaultLookAndFeel()
66 | .findColour (ResizableWindow::backgroundColourId),
67 | DocumentWindow::allButtons)
68 | {
69 | setUsingNativeTitleBar (true);
70 | setContentOwned (createMainContentComponent(), true);
71 | setResizable (true, true);
72 |
73 | centreWithSize (getWidth(), getHeight());
74 | setVisible (true);
75 | }
76 |
77 | void closeButtonPressed() override
78 | {
79 | // This is called when the user tries to close this window. Here, we'll just
80 | // ask the app to quit when this happens, but you can change this to do
81 | // whatever you need.
82 | JUCEApplication::getInstance()->systemRequestedQuit();
83 | }
84 |
85 | /* Note: Be careful if you override any DocumentWindow methods - the base
86 | class uses a lot of them, so by overriding you might break its functionality.
87 | It's best to do all your work in your content component instead, but if
88 | you really have to override any DocumentWindow methods, make sure your
89 | subclass also calls the superclass's method.
90 | */
91 |
92 | private:
93 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainWindow)
94 | };
95 |
96 | private:
97 | ScopedPointer mainWindow;
98 | };
99 |
100 | //==============================================================================
101 | // This macro generates the main() routine that launches the app.
102 | START_JUCE_APPLICATION (AnimationWriterApplication)
103 |
--------------------------------------------------------------------------------
/examples/AnimationWriter/Source/MainComponent.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 |
4 | This file was auto-generated!
5 |
6 | ==============================================================================
7 | */
8 |
9 | #include "../JuceLibraryCode/JuceHeader.h"
10 |
11 | //==============================================================================
12 | /*
13 | This component lives inside our window, and this is where you should put all
14 | your controls and content.
15 | */
16 | class MainContentComponent : public AnimatedAppComponent
17 | {
18 | public:
19 | //==============================================================================
20 | MainContentComponent()
21 | {
22 | counter = -1;
23 | setSize (800, 600);
24 | setFramesPerSecond (25);
25 | FFmpegVideoWriter writer;
26 | DBG (FFmpegVideoWriter::getOutputFormatNames().joinIntoString (";"));
27 | }
28 |
29 | ~MainContentComponent()
30 | {
31 | }
32 |
33 | void mouseDoubleClick (const MouseEvent&) override
34 | {
35 | if (!videoWriter) {
36 | FileChooser chooser ("Save Video File");
37 | if (chooser.browseForFileToSave (true)) {
38 | videoCanvas = Image(Image::RGB, getWidth(), getHeight(), false);
39 | videoWriter = new FFmpegVideoWriter ();
40 | videoWriter->setVideoSize (getWidth(), getHeight());
41 | videoWriter->setVideoCodec (AV_CODEC_ID_PROBE);
42 | videoWriter->setPixelAspect (1, 1);
43 | videoWriter->setPixelFormat (AV_PIX_FMT_YUV420P);
44 | videoWriter->setTimeBase (AVMEDIA_TYPE_VIDEO, av_make_q (1, 25));
45 | videoWriter->openMovieFile (chooser.getResult());
46 | counter = 0;
47 | }
48 | }
49 | }
50 |
51 | void update() override
52 | {
53 | // This function is called at the frequency specified by the setFramesPerSecond() call
54 | // in the constructor. You can use it to update counters, animate values, etc.
55 | if (videoWriter && counter >= 0) {
56 | if (counter > 240) {
57 | videoWriter->closeMovieFile();
58 | videoWriter = nullptr;
59 | counter = -1;
60 | return;
61 | }
62 | Graphics g(videoCanvas);
63 | paint (g);
64 | // videoCanvas = createComponentSnapshot (getLocalBounds());
65 | videoWriter->writeNextVideoFrame (videoCanvas, counter);
66 |
67 | ++counter;
68 | }
69 | }
70 |
71 | void paint (Graphics& g) override
72 | {
73 | // (Our component is opaque, so we must completely fill the background with a solid colour)
74 | g.fillAll (Colours::black);
75 |
76 | g.setColour (Colours::white);
77 | const int fishLength = 15;
78 |
79 | Path spinePath;
80 |
81 | for (int i = 0; i < fishLength; ++i)
82 | {
83 | const float radius = 100 + 10 * std::sin (getFrameCounter() * 0.1f + i * 0.5f);
84 |
85 | Point p (getWidth() / 2.0f + 1.5f * radius * std::sin (getFrameCounter() * 0.02f + i * 0.12f),
86 | getHeight() / 2.0f + 1.0f * radius * std::cos (getFrameCounter() * 0.04f + i * 0.12f));
87 |
88 | // draw the circles along the fish
89 | g.fillEllipse (p.x - i, p.y - i, 2.0f + 2.0f * i, 2.0f + 2.0f * i);
90 |
91 | if (i == 0)
92 | spinePath.startNewSubPath (p); // if this is the first point, start a new path..
93 | else
94 | spinePath.lineTo (p); // ...otherwise add the next point
95 | }
96 |
97 | // draw an outline around the path that we have created
98 | g.strokePath (spinePath, PathStrokeType (4.0f));
99 |
100 | if (!videoWriter)
101 | g.setFont (14.0f);
102 | g.setColour (Colours::red);
103 | g.drawFittedText ("Double-click to start writing", getLocalBounds(),
104 | Justification::bottom, 1);
105 | }
106 |
107 | void resized() override
108 | {
109 | // This is called when the MainContentComponent is resized.
110 | // If you add any child components, this is where you should
111 | // update their positions.
112 | }
113 |
114 |
115 | private:
116 | //==============================================================================
117 |
118 | // Your private member variables go here...
119 | ScopedPointer videoWriter;
120 | Image videoCanvas;
121 | int64 counter;
122 |
123 |
124 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainContentComponent)
125 | };
126 |
127 |
128 | // (This function is called by the app startup code to create our main component)
129 | Component* createMainContentComponent() { return new MainContentComponent(); }
130 |
--------------------------------------------------------------------------------
/examples/VideoPlayer/.gitignore:
--------------------------------------------------------------------------------
1 | Builds/MacOSX/VideoPlayer.xcodeproj/xcuserdata/
2 | Builds/MacOSX/VideoPlayer.xcodeproj/project.xcworkspace/
3 | Builds/MacOSX/build/Debug/
4 | Builds/MacOSX/build/Release/
5 | Builds/MacOSX/build/VideoPlayer.build/
6 | JuceLibraryCode/
7 |
8 |
--------------------------------------------------------------------------------
/examples/VideoPlayer/Builds/MacOSX/Info-App.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | CFBundleExecutable
7 | ${EXECUTABLE_NAME}
8 | CFBundleIconFile
9 |
10 | CFBundleIdentifier
11 | com.yourcompany.VideoLibTest
12 | CFBundleName
13 | VideoPlayer
14 | CFBundleDisplayName
15 | VideoPlayer
16 | CFBundlePackageType
17 | APPL
18 | CFBundleSignature
19 | ????
20 | CFBundleShortVersionString
21 | 1.0.0
22 | CFBundleVersion
23 | 1.0.0
24 | NSHumanReadableCopyright
25 |
26 | NSHighResolutionCapable
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/examples/VideoPlayer/Builds/MacOSX/RecentFilesMenuTemplate.nib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/filmstro/filmstro_ffmpeg/ebb79f7713742311d09ac3f2215d807e88e3a517/examples/VideoPlayer/Builds/MacOSX/RecentFilesMenuTemplate.nib
--------------------------------------------------------------------------------
/examples/VideoPlayer/Builds/VisualStudio2015/VideoPlayer (App).vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 | Debug
9 | Win32
10 |
11 |
12 | Release
13 | Win32
14 |
15 |
16 |
17 | {1F76C5AB-42A2-1C31-68E7-71A7C91907F6}
18 | v140
19 |
20 |
21 |
23 | Application
24 | false
25 | v140
26 |
27 |
29 | Application
30 | false
31 | true
32 | v140
33 |
34 |
35 |
36 |
37 |
40 |
41 |
42 | v140
43 |
44 |
45 | <_ProjectFileVersion>10.0.30319.1
46 | .exe
47 | $(SolutionDir)\$(Platform)\$(Configuration)\App\
48 | $(Platform)\$(Configuration)\App\
49 | VideoLibTest
50 | true
51 | $(SolutionDir)\$(Platform)\$(Configuration)\App\
52 | $(Platform)\$(Configuration)\App\
53 | VideoLibTest
54 | true
55 | v140
56 |
57 |
58 |
59 | _DEBUG;%(PreprocessorDefinitions)
60 | true
61 | true
62 | Win32
63 |
64 |
65 |
66 | Disabled
67 | EditAndContinue
68 | ..\..\JuceLibraryCode;..\..\..\..\modules;..\..\..\..\..\..\JUCE\modules;%(AdditionalIncludeDirectories)
69 | _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2015_78A5022=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;%(PreprocessorDefinitions)
70 | MultiThreadedDebug
71 | true
72 |
73 | $(IntDir)\
74 | $(IntDir)\
75 | $(IntDir)\
76 | Level4
77 | true
78 | true
79 | -I../../../../../../FFmpeg/build/windows/include %(AdditionalOptions)
80 |
81 |
82 | _DEBUG;%(PreprocessorDefinitions)
83 |
84 |
85 | $(OutDir)\VideoLibTest.exe
86 | true
87 | libcmt.lib; msvcrt.lib;;%(IgnoreSpecificDefaultLibraries)
88 | true
89 | $(IntDir)\VideoLibTest.pdb
90 | Windows
91 | MachineX86
92 | false
93 | true
94 | avformat.lib;avutil.lib;avcodec.lib;swscale.lib;swresample.lib;%(AdditionalDependencies)
95 | -LIBPATH:../../../../../../FFmpeg/build/windows/bin %(AdditionalOptions)
96 |
97 |
98 | true
99 | $(IntDir)\VideoLibTest.bsc
100 |
101 |
102 |
103 |
104 | NDEBUG;%(PreprocessorDefinitions)
105 | true
106 | true
107 | Win32
108 |
109 |
110 |
111 | Full
112 | ..\..\JuceLibraryCode;..\..\..\..\modules;..\..\..\..\..\..\JUCE\modules;%(AdditionalIncludeDirectories)
113 | _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2015_78A5022=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;%(PreprocessorDefinitions)
114 | MultiThreaded
115 | true
116 |
117 | $(IntDir)\
118 | $(IntDir)\
119 | $(IntDir)\
120 | Level4
121 | true
122 | true
123 | -I../../../../../../FFmpeg/build/windows/include %(AdditionalOptions)
124 |
125 |
126 | NDEBUG;%(PreprocessorDefinitions)
127 |
128 |
129 | $(OutDir)\VideoLibTest.exe
130 | true
131 | %(IgnoreSpecificDefaultLibraries)
132 | false
133 | $(IntDir)\VideoLibTest.pdb
134 | Windows
135 | MachineX86
136 | true
137 | true
138 | true
139 | avformat.lib;avutil.lib;avcodec.lib;swscale.lib;swresample.lib;%(AdditionalDependencies)
140 | -LIBPATH:../../../../../../FFmpeg/build/windows/bin %(AdditionalOptions)
141 |
142 |
143 | true
144 | $(IntDir)\VideoLibTest.bsc
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
--------------------------------------------------------------------------------
/examples/VideoPlayer/Builds/VisualStudio2015/VideoPlayer - App.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 | Debug
9 | Win32
10 |
11 |
12 | Release
13 | Win32
14 |
15 |
16 |
17 | {1F76C5AB-42A2-1C31-68E7-71A7C91907F6}
18 | v140
19 |
20 |
21 |
23 | Application
24 | false
25 | v140
26 |
27 |
29 | Application
30 | false
31 | true
32 | v140
33 |
34 |
35 |
36 |
37 |
40 |
41 |
42 | v140
43 |
44 |
45 | <_ProjectFileVersion>10.0.30319.1
46 | .exe
47 | $(SolutionDir)\$(Platform)\$(Configuration)\App\
48 | $(Platform)\$(Configuration)\App\
49 | VideoLibTest
50 | true
51 | $(SolutionDir)\$(Platform)\$(Configuration)\App\
52 | $(Platform)\$(Configuration)\App\
53 | VideoLibTest
54 | true
55 | v140
56 |
57 |
58 |
59 | _DEBUG;%(PreprocessorDefinitions)
60 | true
61 | true
62 | Win32
63 |
64 |
65 |
66 | Disabled
67 | EditAndContinue
68 | ..\..\JuceLibraryCode;..\..\..\..\..\..\OpenSource;..\..\..\..\modules;..\..\..\..\..\..\JUCE\modules;%(AdditionalIncludeDirectories)
69 | _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2015_78A5022=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;%(PreprocessorDefinitions)
70 | MultiThreadedDebug
71 | true
72 |
73 | $(IntDir)\
74 | $(IntDir)\
75 | $(IntDir)\
76 | Level4
77 | true
78 | true
79 | -I../../../../../../FFmpeg/build/windows/include %(AdditionalOptions)
80 |
81 |
82 | _DEBUG;%(PreprocessorDefinitions)
83 |
84 |
85 | $(OutDir)\VideoLibTest.exe
86 | true
87 | libcmt.lib; msvcrt.lib;;%(IgnoreSpecificDefaultLibraries)
88 | true
89 | $(IntDir)\VideoLibTest.pdb
90 | Windows
91 | MachineX86
92 | false
93 | true
94 | avformat.lib;avutil.lib;avcodec.lib;swscale.lib;swresample.lib;%(AdditionalDependencies)
95 | -LIBPATH:../../../../../../FFmpeg/build/windows/bin %(AdditionalOptions)
96 |
97 |
98 | true
99 | $(IntDir)\VideoLibTest.bsc
100 |
101 |
102 |
103 |
104 | NDEBUG;%(PreprocessorDefinitions)
105 | true
106 | true
107 | Win32
108 |
109 |
110 |
111 | Full
112 | ..\..\JuceLibraryCode;..\..\..\..\..\..\OpenSource;..\..\..\..\modules;..\..\..\..\..\..\JUCE\modules;%(AdditionalIncludeDirectories)
113 | _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2015_78A5022=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;%(PreprocessorDefinitions)
114 | MultiThreaded
115 | true
116 |
117 | $(IntDir)\
118 | $(IntDir)\
119 | $(IntDir)\
120 | Level4
121 | true
122 | true
123 | -I../../../../../../FFmpeg/build/windows/include %(AdditionalOptions)
124 |
125 |
126 | NDEBUG;%(PreprocessorDefinitions)
127 |
128 |
129 | $(OutDir)\VideoLibTest.exe
130 | true
131 | %(IgnoreSpecificDefaultLibraries)
132 | false
133 | $(IntDir)\VideoLibTest.pdb
134 | Windows
135 | MachineX86
136 | true
137 | true
138 | true
139 | avformat.lib;avutil.lib;avcodec.lib;swscale.lib;swresample.lib;%(AdditionalDependencies)
140 | -LIBPATH:../../../../../../FFmpeg/build/windows/bin %(AdditionalOptions)
141 |
142 |
143 | true
144 | $(IntDir)\VideoLibTest.bsc
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
--------------------------------------------------------------------------------
/examples/VideoPlayer/Builds/VisualStudio2015/VideoPlayer.sln:
--------------------------------------------------------------------------------
1 | Microsoft Visual Studio Solution File, Format Version 11.00
2 | # Visual Studio 2015
3 |
4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VideoPlayer - App", "VideoPlayer_App.vcxproj", "{1F76C5AB-42A2-1C31-68E7-71A7C91907F6}"
5 | EndProject
6 | Global
7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
8 | Debug|Win32 = Debug|Win32
9 | Release|Win32 = Release|Win32
10 | EndGlobalSection
11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
12 | {1F76C5AB-42A2-1C31-68E7-71A7C91907F6}.Debug|Win32.ActiveCfg = Debug|Win32
13 | {1F76C5AB-42A2-1C31-68E7-71A7C91907F6}.Debug|Win32.Build.0 = Debug|Win32
14 | {1F76C5AB-42A2-1C31-68E7-71A7C91907F6}.Release|Win32.ActiveCfg = Release|Win32
15 | {1F76C5AB-42A2-1C31-68E7-71A7C91907F6}.Release|Win32.Build.0 = Release|Win32
16 | EndGlobalSection
17 | GlobalSection(SolutionProperties) = preSolution
18 | HideSolutionNode = FALSE
19 | EndGlobalSection
20 | EndGlobal
21 |
--------------------------------------------------------------------------------
/examples/VideoPlayer/Builds/VisualStudio2015/resources.rc:
--------------------------------------------------------------------------------
1 | #ifdef JUCE_USER_DEFINED_RC_FILE
2 | #include JUCE_USER_DEFINED_RC_FILE
3 | #else
4 |
5 | #undef WIN32_LEAN_AND_MEAN
6 | #define WIN32_LEAN_AND_MEAN
7 | #include
8 |
9 | VS_VERSION_INFO VERSIONINFO
10 | FILEVERSION 1,0,0,0
11 | BEGIN
12 | BLOCK "StringFileInfo"
13 | BEGIN
14 | BLOCK "040904E4"
15 | BEGIN
16 | VALUE "FileDescription", "VideoPlayer\0"
17 | VALUE "FileVersion", "1.0.0\0"
18 | VALUE "ProductName", "VideoPlayer\0"
19 | VALUE "ProductVersion", "1.0.0\0"
20 | END
21 | END
22 |
23 | BLOCK "VarFileInfo"
24 | BEGIN
25 | VALUE "Translation", 0x409, 1252
26 | END
27 | END
28 |
29 | #endif
30 |
--------------------------------------------------------------------------------
/examples/VideoPlayer/Source/Main.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 |
4 | Copyright (c) 2017, Filmstro Ltd. - Daniel Walz
5 | All rights reserved.
6 |
7 | Redistribution and use in source and binary forms, with or without modification,
8 | are permitted provided that the following conditions are met:
9 | 1. Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 | 2. Redistributions in binary form must reproduce the above copyright notice,
12 | this list of conditions and the following disclaimer in the documentation
13 | and/or other materials provided with the distribution.
14 | 3. Neither the name of the copyright holder nor the names of its contributors
15 | may be used to endorse or promote products derived from this software without
16 | specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
27 | OF THE POSSIBILITY OF SUCH DAMAGE.
28 | ==============================================================================
29 |
30 | This contains the basic startup code for a Juce application.
31 |
32 | ==============================================================================
33 | */
34 |
35 | #include "../JuceLibraryCode/JuceHeader.h"
36 |
37 | Component* createMainContentComponent();
38 |
39 | //==============================================================================
40 | class VideoPlayerApplication : public JUCEApplication
41 | {
42 | public:
43 | //==============================================================================
44 | VideoPlayerApplication() {}
45 |
46 | const String getApplicationName() override { return ProjectInfo::projectName; }
47 | const String getApplicationVersion() override { return ProjectInfo::versionString; }
48 | bool moreThanOneInstanceAllowed() override { return true; }
49 |
50 | //==============================================================================
51 | void initialise (const String& commandLine) override
52 | {
53 | // This method is where you should put your application's initialisation code..
54 |
55 | mainWindow = new MainWindow (getApplicationName());
56 | }
57 |
58 | void shutdown() override
59 | {
60 | // Add your application's shutdown code here..
61 |
62 | mainWindow = nullptr; // (deletes our window)
63 | }
64 |
65 | //==============================================================================
66 | void systemRequestedQuit() override
67 | {
68 | // This is called when the app is being asked to quit: you can ignore this
69 | // request and let the app carry on running, or call quit() to allow the app to close.
70 | quit();
71 | }
72 |
73 | void anotherInstanceStarted (const String& commandLine) override
74 | {
75 | // When another instance of the app is launched while this one is running,
76 | // this method is invoked, and the commandLine parameter tells you what
77 | // the other instance's command-line arguments were.
78 | }
79 |
80 | //==============================================================================
81 | /*
82 | This class implements the desktop window that contains an instance of
83 | our MainContentComponent class.
84 | */
85 | class MainWindow : public DocumentWindow
86 | {
87 | public:
88 | MainWindow (String name) : DocumentWindow (name,
89 | Colours::lightgrey,
90 | DocumentWindow::allButtons)
91 | {
92 | setUsingNativeTitleBar (true);
93 | setContentOwned (createMainContentComponent(), true);
94 | setResizable (true, true);
95 |
96 | centreWithSize (getWidth(), getHeight());
97 | setVisible (true);
98 | }
99 |
100 | void closeButtonPressed() override
101 | {
102 | // This is called when the user tries to close this window. Here, we'll just
103 | // ask the app to quit when this happens, but you can change this to do
104 | // whatever you need.
105 | JUCEApplication::getInstance()->systemRequestedQuit();
106 | }
107 |
108 | /* Note: Be careful if you override any DocumentWindow methods - the base
109 | class uses a lot of them, so by overriding you might break its functionality.
110 | It's best to do all your work in your content component instead, but if
111 | you really have to override any DocumentWindow methods, make sure your
112 | subclass also calls the superclass's method.
113 | */
114 |
115 | private:
116 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainWindow)
117 | };
118 |
119 | private:
120 | ScopedPointer mainWindow;
121 | };
122 |
123 | //==============================================================================
124 | // This macro generates the main() routine that launches the app.
125 | START_JUCE_APPLICATION (VideoPlayerApplication)
126 |
--------------------------------------------------------------------------------
/examples/VideoPlayer/Source/MainComponent.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 | Copyright (c) 2017, Filmstro Ltd. - Daniel Walz
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without modification,
7 | are permitted provided that the following conditions are met:
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 | 3. Neither the name of the copyright holder nor the names of its contributors
14 | may be used to endorse or promote products derived from this software without
15 | specific prior written permission.
16 |
17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
26 | OF THE POSSIBILITY OF SUCH DAMAGE.
27 | ==============================================================================
28 |
29 | Demo to play back a movie using ffmpeg and JUCE
30 |
31 | ==============================================================================
32 | */
33 |
34 | #ifndef MAINCOMPONENT_H_INCLUDED
35 | #define MAINCOMPONENT_H_INCLUDED
36 |
37 | #include "../JuceLibraryCode/JuceHeader.h"
38 |
39 | #include "OSDComponent.h"
40 |
41 | //==============================================================================
42 | /*
43 | This component lives inside our window, and this is where you should put all
44 | your controls and content.
45 | */
46 | class VideoComponentWithDropper : public FFmpegVideoComponent,
47 | public FileDragAndDropTarget
48 | {
49 | public:
50 | VideoComponentWithDropper (FFmpegVideoReader* readerToOpenFiles)
51 | {
52 | setWantsKeyboardFocus (false);
53 | setVideoReader (readerToOpenFiles);
54 | }
55 |
56 | virtual ~VideoComponentWithDropper () {}
57 |
58 | bool isInterestedInFileDrag (const StringArray &files) override
59 | {
60 | return true;
61 | }
62 |
63 | void filesDropped (const StringArray &files, int x, int y) override
64 | {
65 | if (FFmpegVideoReader* reader = getVideoReader()) {
66 | File fileToOpen (files [0]);
67 | reader->loadMovieFile (fileToOpen);
68 | Process::makeForegroundProcess ();
69 | }
70 | }
71 | };
72 |
73 | //==============================================================================
74 | /*
75 | This component lives inside our window, and this is where you should put all
76 | your controls and content.
77 | */
78 | class MainContentComponent : public AudioAppComponent,
79 | public FFmpegVideoListener
80 | {
81 | public:
82 | //==============================================================================
83 | MainContentComponent()
84 | {
85 | setWantsKeyboardFocus (true);
86 | videoAspectRatio = 1.77;
87 |
88 | videoReader = new FFmpegVideoReader (384000, 30);
89 | videoReader->addVideoListener (this);
90 |
91 | transportSource = new AudioTransportSource ();
92 | transportSource->setSource (videoReader, 0, nullptr);
93 |
94 | videoComponent = new VideoComponentWithDropper (videoReader);
95 | addAndMakeVisible (videoComponent);
96 |
97 | osdComponent = new OSDComponent (videoReader, transportSource);
98 | addAndMakeVisible (osdComponent);
99 |
100 | // specify the number of input and output channels that we want to open
101 | setAudioChannels (0, 2);
102 |
103 | #ifdef DEBUG
104 | if (AudioIODevice* device = deviceManager.getCurrentAudioDevice()) {
105 | DBG ("Current Samplerate: " + String (device->getCurrentSampleRate()));
106 | DBG ("Current Buffersize: " + String (device->getCurrentBufferSizeSamples()));
107 | DBG ("Current Bitdepth: " + String (device->getCurrentBitDepth()));
108 | }
109 | #endif /* DEBUG */
110 |
111 | #ifdef USE_FF_AUDIO_METERS
112 | meter = new LevelMeter ();
113 | meter->getLookAndFeel()->setMeterColour (LevelMeterLookAndFeel::lmBackgroundColour,
114 | Colour::fromFloatRGBA (0.0f, 0.0f, 0.0f, 0.6f));
115 | meter->setMeterSource (&meterSource);
116 | addAndMakeVisible (meter);
117 | #endif
118 |
119 | setSize (800, 600);
120 | }
121 |
122 | ~MainContentComponent()
123 | {
124 | shutdownAudio();
125 | }
126 |
127 | //==============================================================================
128 | void prepareToPlay (int samplesPerBlockExpected, double sampleRate) override
129 | {
130 | // This function will be called when the audio device is started, or when
131 | // its settings (i.e. sample rate, block size, etc) are changed.
132 | if (videoReader) videoReader->prepareToPlay (samplesPerBlockExpected, sampleRate);
133 | if (transportSource) transportSource->prepareToPlay (samplesPerBlockExpected, sampleRate);
134 |
135 | readBuffer.setSize (2, samplesPerBlockExpected);
136 | }
137 |
138 | void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill) override
139 | {
140 | auto numInputChannels = videoReader->getVideoChannels();
141 |
142 | AudioSourceChannelInfo info (&readBuffer,
143 | bufferToFill.startSample,
144 | bufferToFill.numSamples);
145 | // the AudioTransportSource takes care of start, stop and resample
146 | transportSource->getNextAudioBlock (info);
147 |
148 | #ifdef USE_FF_AUDIO_METERS
149 | meterSource.measureBlock (readBuffer);
150 | #endif
151 |
152 | if (numInputChannels > 0)
153 | {
154 | for (int i=0; i < bufferToFill.buffer->getNumChannels(); ++i) {
155 |
156 | bufferToFill.buffer->copyFrom (i, bufferToFill.startSample,
157 | readBuffer.getReadPointer (i % numInputChannels),
158 | bufferToFill.numSamples);
159 | if (bufferToFill.buffer->getNumChannels() == 2 &&
160 | readBuffer.getNumChannels() > 2) {
161 | // add center to left and right
162 | bufferToFill.buffer->addFrom (i, bufferToFill.startSample,
163 | readBuffer.getReadPointer (2),
164 | bufferToFill.numSamples, 0.7);
165 | }
166 | }
167 | }
168 | else{
169 | bufferToFill.clearActiveBufferRegion();
170 | }
171 | }
172 |
173 | void releaseResources() override
174 | {
175 | transportSource->releaseResources ();
176 | videoReader->releaseResources ();
177 | }
178 |
179 | //==============================================================================
180 | /** Reset gui when a new file is loaded */
181 | void videoFileChanged (const juce::File& video) override
182 | {
183 | String abbrev (video.getFullPathName());
184 | if (abbrev.length() > 30)
185 | abbrev = "(...)" + abbrev.substring (abbrev.length() - 30);
186 | DBG ("====================================================");
187 | DBG ("Loaded file : " + abbrev);
188 | DBG ("Channels: " + String (videoReader->getVideoChannels()));
189 | DBG ("Duration (sec): " + String (videoReader->getVideoDuration()));
190 | DBG ("Framerate (1/sec): " + String (videoReader->getFramesPerSecond()));
191 | DBG ("SampleRate: " + String (videoReader->getVideoSamplingRate()));
192 | DBG ("SampleFormat: " + String (av_get_sample_fmt_name (videoReader->getSampleFormat())));
193 | DBG ("Width: " + String (videoReader->getVideoWidth()));
194 | DBG ("Height: " + String (videoReader->getVideoHeight()));
195 | DBG ("Pixel format: " + String (av_get_pix_fmt_name (videoReader->getPixelFormat())));
196 | DBG ("Pixel aspect ratio:" + String (videoReader->getVideoPixelAspect()));
197 | DBG ("====================================================");
198 |
199 | osdComponent->setVideoLength (videoReader->getVideoDuration ());
200 |
201 | transportSource->setSource (videoReader, 0, nullptr, videoReader->getVideoSamplingRate(), videoReader->getVideoChannels());
202 | readBuffer.setSize (videoReader->getVideoChannels(), readBuffer.getNumSamples());
203 |
204 | videoAspectRatio = videoReader->getVideoAspectRatio ();
205 | resized ();
206 |
207 | if (AudioIODevice* device = deviceManager.getCurrentAudioDevice()) {
208 | videoReader->prepareToPlay (device->getCurrentBufferSizeSamples(),
209 | device->getCurrentSampleRate());
210 | readBuffer.setSize (videoReader->getVideoChannels(),
211 | device->getCurrentBufferSizeSamples());
212 |
213 | }
214 | }
215 |
216 | void presentationTimestampChanged (const double pts) override
217 | {
218 | MessageManager::callAsync (std::bind (&OSDComponent::setCurrentTime,
219 | osdComponent.get(),
220 | videoReader->getCurrentTimeStamp()));
221 | }
222 |
223 | void paint (Graphics& g) override
224 | {
225 | g.fillAll (Colours::black);
226 | }
227 |
228 | void resized() override
229 | {
230 | videoComponent->setBounds (getBounds());
231 | osdComponent->setBounds (getBounds());
232 |
233 | #ifdef USE_FF_AUDIO_METERS
234 | const int w = 30 + 20 * videoReader->getVideoChannels();
235 | meter->setBounds (getWidth() - w, getHeight() - 240, w, 200);
236 | #endif
237 | }
238 |
239 | bool keyPressed (const KeyPress &key) override
240 | {
241 | if (key == KeyPress::spaceKey) {
242 | if (transportSource->isPlaying()) {
243 | transportSource->stop();
244 | return true;
245 | }
246 | transportSource->start();
247 | return true;
248 | }
249 | return false;
250 | }
251 |
252 | private:
253 | //==============================================================================
254 |
255 | // Your private member variables go here...
256 | ScopedPointer videoComponent;
257 | ScopedPointer videoReader;
258 | ScopedPointer osdComponent;
259 | ScopedPointer transportSource;
260 |
261 | #ifdef USE_FF_AUDIO_METERS
262 | ScopedPointer meter;
263 | LevelMeterSource meterSource;
264 | #endif
265 |
266 | AudioSampleBuffer readBuffer;
267 |
268 | double videoAspectRatio;
269 |
270 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainContentComponent)
271 | };
272 |
273 |
274 | // (This function is called by the app startup code to create our main component)
275 | Component* createMainContentComponent() { return new MainContentComponent(); }
276 |
277 |
278 | #endif // MAINCOMPONENT_H_INCLUDED
279 |
--------------------------------------------------------------------------------
/examples/VideoPlayer/Source/OSDComponent.h:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 | Copyright (c) 2017, Filmstro Ltd. - Daniel Walz
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without modification,
7 | are permitted provided that the following conditions are met:
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 | 3. Neither the name of the copyright holder nor the names of its contributors
14 | may be used to endorse or promote products derived from this software without
15 | specific prior written permission.
16 |
17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
26 | OF THE POSSIBILITY OF SUCH DAMAGE.
27 | ==============================================================================
28 |
29 | Overlay component
30 |
31 | ==============================================================================
32 | */
33 |
34 |
35 | #ifndef OSDCOMPONENT_H_INCLUDED
36 | #define OSDCOMPONENT_H_INCLUDED
37 |
38 | #include "../JuceLibraryCode/JuceHeader.h"
39 |
40 | //==============================================================================
41 | /*
42 | */
43 | class OSDComponent : public Component,
44 | public Slider::Listener,
45 | public Button::Listener
46 | {
47 | public:
48 | OSDComponent (FFmpegVideoReader* readerToControl, AudioTransportSource* transportToControl)
49 | : videoReader (readerToControl), transport (transportToControl)
50 | {
51 | ffwdSpeed = 2;
52 |
53 | setInterceptsMouseClicks (false, true);
54 | setWantsKeyboardFocus (false);
55 |
56 | openFile = new TextButton ("Open", "Open");
57 | openFile->addListener (this);
58 | openFile->setWantsKeyboardFocus (false);
59 | addAndMakeVisible (openFile);
60 | flexBox.items.add (FlexItem (*openFile).withFlex (1.0, 1.0, 0.5).withHeight (20.0));
61 |
62 | saveFile = new TextButton ("Save", "Save");
63 | saveFile->addListener (this);
64 | saveFile->setWantsKeyboardFocus (false);
65 | addAndMakeVisible (saveFile);
66 | flexBox.items.add (FlexItem (*saveFile).withFlex (1.0, 1.0, 0.5).withHeight (20.0));
67 |
68 | seekBar = new Slider (Slider::LinearHorizontal, Slider::NoTextBox);
69 | addAndMakeVisible (seekBar);
70 | seekBar->addListener (this);
71 | seekBar->setWantsKeyboardFocus (false);
72 | flexBox.items.add (FlexItem (*seekBar).withFlex (6.0, 1.0, 0.5).withHeight (20.0));
73 |
74 | stop = new TextButton ("Stop", "Stop");
75 | stop->addListener (this);
76 | stop->setWantsKeyboardFocus (false);
77 | addAndMakeVisible (stop);
78 | flexBox.items.add (FlexItem (*stop).withFlex (1.0, 1.0, 0.5).withHeight (20.0));
79 |
80 | pause = new TextButton ("Pause", "Pause");
81 | pause->addListener (this);
82 | pause->setWantsKeyboardFocus (false);
83 | addAndMakeVisible (pause);
84 | flexBox.items.add (FlexItem (*pause).withFlex (1.0, 1.0, 0.5).withHeight (20.0));
85 |
86 | play = new TextButton ("Play", "Play");
87 | play->addListener (this);
88 | play->setWantsKeyboardFocus (false);
89 | addAndMakeVisible (play);
90 | flexBox.items.add (FlexItem (*play).withFlex (1.0, 1.0, 0.5).withHeight (20.0));
91 |
92 | ffwd = new TextButton ("FFWD", "FFWD");
93 | ffwd->addListener (this);
94 | ffwd->setWantsKeyboardFocus (false);
95 | addAndMakeVisible (ffwd);
96 | flexBox.items.add (FlexItem (*ffwd).withFlex (1.0, 1.0, 0.5).withHeight (20.0));
97 |
98 | openFile->setConnectedEdges (TextButton::ConnectedOnRight);
99 | saveFile->setConnectedEdges (TextButton::ConnectedOnLeft);
100 |
101 | stop->setConnectedEdges (TextButton::ConnectedOnRight);
102 | pause->setConnectedEdges (TextButton::ConnectedOnRight | TextButton::ConnectedOnLeft);
103 | play->setConnectedEdges (TextButton::ConnectedOnRight | TextButton::ConnectedOnLeft);
104 | ffwd->setConnectedEdges (TextButton::ConnectedOnLeft);
105 |
106 | idle = new MouseIdle (*this);
107 | }
108 |
109 | ~OSDComponent()
110 | {
111 | }
112 |
113 | void paint (Graphics& g) override
114 | {
115 | if (videoReader && videoReader->getVideoDuration() > 0) {
116 | g.setColour (Colours::white);
117 | g.setFont (24);
118 | String dim = String (videoReader->getVideoWidth()) + " x " + String (videoReader->getVideoHeight());
119 | g.drawFittedText (dim, getLocalBounds(), Justification::topLeft, 1);
120 | g.drawFittedText (FFmpegVideoReader::formatTimeCode (videoReader->getCurrentTimeStamp ()),
121 | getLocalBounds(), Justification::topRight, 1);
122 | }
123 | }
124 |
125 | void resized() override
126 | {
127 | Rectangle bounds = getBounds().withTop (getHeight() - 40);
128 | flexBox.performLayout (bounds);
129 | }
130 |
131 | void setCurrentTime (const double time)
132 | {
133 | seekBar->setValue (time, dontSendNotification);
134 | }
135 |
136 | void setVideoLength (const double length)
137 | {
138 | seekBar->setRange (0.0, length);
139 | }
140 |
141 | /** React to slider changes with seeking */
142 | void sliderValueChanged (juce::Slider* slider) override
143 | {
144 | if (slider == seekBar) {
145 | videoReader->setNextReadPosition (slider->getValue() * videoReader->getVideoSamplingRate());
146 | }
147 | }
148 |
149 | void buttonClicked (Button* b) override
150 | {
151 | if (b == openFile) {
152 | transport->stop();
153 | FileChooser chooser ("Open Video File");
154 | if (chooser.browseForFileToOpen()) {
155 | File video = chooser.getResult();
156 | videoReader->loadMovieFile (video);
157 |
158 | }
159 | }
160 | else if (b == play) {
161 | if (ffwdSpeed != 2) {
162 | int64 lastPos = videoReader->getNextReadPosition();
163 | ffwdSpeed = 2;
164 | double factor = 0.5 + (ffwdSpeed / 4.0);
165 | transport->setSource (videoReader, 0, nullptr, videoReader->getVideoSamplingRate() * factor, videoReader->getVideoChannels());
166 | videoReader->setNextReadPosition (lastPos);
167 | }
168 | transport->start();
169 | }
170 | else if (b == stop) {
171 | transport->stop();
172 | videoReader->setNextReadPosition (0);
173 | }
174 | else if (b == pause) {
175 | transport->stop();
176 | }
177 | else if (b == ffwd) {
178 | int64 lastPos = videoReader->getNextReadPosition();
179 | ffwdSpeed = ++ffwdSpeed % 7;
180 | double factor = 0.5 + (ffwdSpeed / 4.0);
181 | transport->setSource (videoReader, 0, nullptr, videoReader->getVideoSamplingRate() * factor, videoReader->getVideoChannels());
182 | videoReader->setNextReadPosition (lastPos);
183 | transport->start ();
184 |
185 | }
186 | else if (b == saveFile) {
187 | transport->stop();
188 | FileChooser chooser ("Save Video File");
189 | if (chooser.browseForFileToSave (true)) {
190 | File saveFileName = chooser.getResult();
191 |
192 | FFmpegVideoReader copyReader;
193 |
194 | FFmpegVideoWriter writer;
195 | copyReader.addVideoListener (&writer);
196 | copyReader.loadMovieFile (videoReader->getVideoFileName());
197 | copyReader.prepareToPlay (1024, videoReader->getVideoSamplingRate());
198 |
199 | AVRational videoTimeBase = copyReader.getVideoTimeBase();
200 | if (videoTimeBase.num > 0) {
201 | writer.setTimeBase (AVMEDIA_TYPE_VIDEO, videoTimeBase);
202 | }
203 | writer.setVideoCodec (AV_CODEC_ID_PROBE);
204 | writer.setAudioCodec (AV_CODEC_ID_PROBE);
205 | writer.setVideoSize (copyReader.getVideoWidth(), copyReader.getVideoHeight());
206 | writer.setPixelFormat (copyReader.getPixelFormat());
207 | writer.openMovieFile (saveFileName);
208 |
209 | AudioBuffer buffer;
210 | buffer.setSize (2, 1024);
211 |
212 | while (copyReader.getCurrentTimeStamp() < copyReader.getVideoDuration()) {
213 | AudioSourceChannelInfo info (&buffer, 0, 1024);
214 | copyReader.waitForNextAudioBlockReady (info, 500);
215 | copyReader.getNextAudioBlock (info);
216 |
217 | writer.writeNextAudioBlock (info);
218 | }
219 | writer.closeMovieFile ();
220 |
221 | copyReader.removeVideoListener (&writer);
222 | }
223 | }
224 | }
225 |
226 | class MouseIdle : public MouseListener, public Timer
227 | {
228 | public:
229 | MouseIdle (Component& c) :
230 | component (c),
231 | lastMovement (Time::getMillisecondCounter())
232 | {
233 | Desktop::getInstance().addGlobalMouseListener (this);
234 | startTimerHz (20);
235 | }
236 |
237 | void timerCallback () override
238 | {
239 | const int64 relTime = Time::getMillisecondCounter() - lastMovement;
240 | if (relTime < 2000) {
241 | component.setVisible (true);
242 | component.setAlpha (1.0);
243 | if (Component* parent = component.getParentComponent())
244 | parent->setMouseCursor (MouseCursor::StandardCursorType::NormalCursor);
245 | }
246 | else if (relTime < 2300) {
247 | component.setAlpha (1.0 - jmax (0.0, (relTime - 2000.0) / 300.0));
248 | }
249 | else {
250 | component.setVisible (false);
251 | if (Component* parent = component.getParentComponent()) {
252 | parent->setMouseCursor (MouseCursor::StandardCursorType::NoCursor);
253 | Desktop::getInstance().getMainMouseSource().forceMouseCursorUpdate();
254 | }
255 | }
256 | }
257 |
258 | void mouseMove (const MouseEvent &event) override
259 | {
260 | if (event.position.getDistanceFrom (lastPosition) > 3.0) {
261 | lastMovement = Time::getMillisecondCounter();
262 | lastPosition = event.position;
263 | }
264 | }
265 | private:
266 | Component& component;
267 | int64 lastMovement;
268 | Point lastPosition;
269 | };
270 |
271 | private:
272 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OSDComponent)
273 |
274 | FlexBox flexBox;
275 |
276 | ScopedPointer idle;
277 | ScopedPointer seekBar;
278 | ScopedPointer openFile;
279 | ScopedPointer saveFile;
280 | ScopedPointer play;
281 | ScopedPointer pause;
282 | ScopedPointer stop;
283 | ScopedPointer ffwd;
284 | int ffwdSpeed;
285 | FFmpegVideoReader* videoReader;
286 |
287 | AudioTransportSource* transport;
288 | };
289 |
290 |
291 | #endif // OSDCOMPONENT_H_INCLUDED
292 |
--------------------------------------------------------------------------------
/examples/VideoPlayer/VideoPlayer.jucer:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
10 |
12 |
13 |
14 |
15 |
16 |
19 |
20 |
23 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
47 |
48 |
51 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/modules/filmstro_audiohelpers/filmstro_audiohelpers.h:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 | Copyright (c) 2017 Filmstro Ltd. - Daniel Walz
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without modification,
7 | are permitted provided that the following conditions are met:
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 | 3. Neither the name of the copyright holder nor the names of its contributors
14 | may be used to endorse or promote products derived from this software without
15 | specific prior written permission.
16 |
17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
26 | OF THE POSSIBILITY OF SUCH DAMAGE.
27 | ==============================================================================
28 |
29 | BEGIN_JUCE_MODULE_DECLARATION
30 |
31 | ID: filmstro_audiohelpers
32 | vendor: Filmstro Ltd.
33 | version: 0.9.0
34 | name: Basic audio helper classes
35 | description: Audio helper classes of general purpose
36 | dependencies: juce_audio_basics, juce_audio_formats, juce_audio_devices, juce_audio_processors
37 | website: http://www.filmstro.com/
38 | license: BSD V2 3-clause
39 |
40 | END_JUCE_MODULE_DECLARATION
41 |
42 | ==============================================================================
43 | */
44 |
45 |
46 | #ifndef FILMSTRO_AUDIOHELPERS_INCLUDED_H
47 | #define FILMSTRO_AUDIOHELPERS_INCLUDED_H
48 |
49 |
50 | #include
51 | #include
52 | #include
53 | #include
54 |
55 | #include "filmstro_audiohelpers/filmstro_audiohelpers_AudioBufferFIFO.h"
56 | #include "filmstro_audiohelpers/filmstro_audiohelpers_AudioProcessorPlayerSource.h"
57 | #include "filmstro_audiohelpers/filmstro_audiohelpers_OutputSourcePlayer.h"
58 | #include "filmstro_audiohelpers/filmstro_audiohelpers_SharedFormatManager.h"
59 |
60 | #endif /* FILMSTRO_AUDIOHELPERS_INCLUDED_H */
61 |
62 |
--------------------------------------------------------------------------------
/modules/filmstro_audiohelpers/filmstro_audiohelpers_AudioBufferFIFO.h:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 | Copyright (c) 2017, Filmstro Ltd. - Daniel Walz
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without modification,
7 | are permitted provided that the following conditions are met:
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 | 3. Neither the name of the copyright holder nor the names of its contributors
14 | may be used to endorse or promote products derived from this software without
15 | specific prior written permission.
16 |
17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
26 | OF THE POSSIBILITY OF SUCH DAMAGE.
27 | ==============================================================================
28 | \class AudioBufferFIFO
29 | \file filmstro_audiobasics_AudioBufferFIFO.h
30 | \brief A FIFO for audio samples
31 |
32 | \author Daniel Walz / Filmstro Ltd.
33 | \date September 7th 2016
34 |
35 | \description A FIFO for AudioBuffer / samples
36 |
37 | ==============================================================================
38 | */
39 |
40 | #ifndef FSPRO_AUDIOBASICS_AUDIOBUFFERFIFO_H_INCLUDED
41 | #define FSPRO_AUDIOBASICS_AUDIOBUFFERFIFO_H_INCLUDED
42 |
43 | /**
44 | The AudioBufferFIFO implements an actual sample buffer using JUCEs AbstractFIFO
45 | class. You can add samples from the various kind of formats, like float pointers
46 | or AudioBuffers. Then you can read into float arrays, AudioBuffers or even
47 | AudioSourceChannelInfo to be used directly in AudioSources.
48 | */
49 | template
50 | class AudioBufferFIFO : public juce::AbstractFifo
51 | {
52 | public:
53 | /*< Creates a FIFO with a buffer of given number of channels and given number of samples */
54 | AudioBufferFIFO (int channels, int buffersize) :
55 | AbstractFifo (buffersize)
56 | {
57 | buffer.setSize (channels, buffersize);
58 | }
59 |
60 | /*< Resize the buffer with new number of channels and new number of samples */
61 | void setSize (const int channels, const int newBufferSize)
62 | {
63 | buffer.setSize (channels, newBufferSize);
64 | setTotalSize (newBufferSize);
65 | reset ();
66 | }
67 |
68 | /*< Push samples into the FIFO from raw float arrays */
69 | void addToFifo (const FloatType** samples, int numSamples)
70 | {
71 | jassert (getFreeSpace() >= numSamples);
72 | int start1, size1, start2, size2;
73 | prepareToWrite (numSamples, start1, size1, start2, size2);
74 | if (size1 > 0)
75 | for (int channel = 0; channel < buffer.getNumChannels(); ++channel)
76 | buffer.copyFrom (channel, start1, samples[channel], size1);
77 | if (size2 > 0)
78 | for (int channel = 0; channel < buffer.getNumChannels(); ++channel)
79 | buffer.copyFrom (channel, start2, samples[channel] + size1, size2);
80 | finishedWrite (size1 + size2);
81 | }
82 |
83 | /*< Push samples from an AudioBuffer into the FIFO */
84 | void addToFifo (const juce::AudioBuffer& samples, int numSamples = -1, int sourceOffset = 0)
85 | {
86 | const int addSamples = (numSamples < 0 ? samples.getNumSamples() : numSamples) - sourceOffset;
87 | jassert (getFreeSpace() >= addSamples);
88 |
89 | int start1, size1, start2, size2;
90 | prepareToWrite (addSamples, start1, size1, start2, size2);
91 | if (size1 > 0)
92 | for (int channel = 0; channel < buffer.getNumChannels(); ++channel)
93 | buffer.copyFrom (channel, start1, samples.getReadPointer (channel, sourceOffset), size1);
94 | if (size2 > 0)
95 | for (int channel = 0; channel < buffer.getNumChannels(); ++channel)
96 | buffer.copyFrom (channel, start2, samples.getReadPointer (channel, sourceOffset + size1), size2);
97 | finishedWrite (size1 + size2);
98 |
99 | }
100 |
101 | /*< Read samples from the FIFO into raw float arrays */
102 | void readFromFifo (FloatType** samples, int numSamples)
103 | {
104 | jassert (getNumReady() >= numSamples);
105 | int start1, size1, start2, size2;
106 | prepareToRead (numSamples, start1, size1, start2, size2);
107 | if (size1 > 0)
108 | for (int channel = 0; channel < buffer.getNumChannels(); ++channel)
109 | juce::FloatVectorOperations::copy (samples [channel],
110 | buffer.getReadPointer (channel, start1),
111 | size1);
112 | if (size2 > 0)
113 | for (int channel = 0; channel < buffer.getNumChannels(); ++channel)
114 | juce::FloatVectorOperations::copy (samples [channel] + size1,
115 | buffer.getReadPointer (channel, start2),
116 | size2);
117 | finishedRead (size1 + size2);
118 | }
119 |
120 | /*< Read samples from the FIFO into AudioBuffers */
121 | void readFromFifo (juce::AudioBuffer& samples, int numSamples=-1)
122 | {
123 | const int readSamples = numSamples > 0 ? numSamples : samples.getNumSamples();
124 | jassert (getNumReady() >= readSamples);
125 |
126 | int start1, size1, start2, size2;
127 | prepareToRead (readSamples, start1, size1, start2, size2);
128 | if (size1 > 0)
129 | for (int channel = 0; channel < buffer.getNumChannels(); ++channel)
130 | samples.copyFrom (channel, 0, buffer.getReadPointer (channel, start1), size1);
131 | if (size2 > 0)
132 | for (int channel = 0; channel < buffer.getNumChannels(); ++channel)
133 | samples.copyFrom (channel, size1, buffer.getReadPointer (channel, start2), size2);
134 | finishedRead (size1 + size2);
135 | }
136 |
137 | /*< Read samples from the FIFO into AudioSourceChannelInfo buffers to be used in AudioSources getNextAudioBlock */
138 | void readFromFifo (const juce::AudioSourceChannelInfo& info, int numSamples=-1)
139 | {
140 | const int readSamples = numSamples > 0 ? numSamples : info.numSamples;
141 | jassert (getNumReady() >= readSamples);
142 |
143 | int start1, size1, start2, size2;
144 | prepareToRead (readSamples, start1, size1, start2, size2);
145 | if (size1 > 0)
146 | for (int channel = 0; channel < info.buffer->getNumChannels(); ++channel)
147 | info.buffer->copyFrom (channel, info.startSample, buffer.getReadPointer (channel, start1), size1);
148 | if (size2 > 0)
149 | for (int channel = 0; channel < info.buffer->getNumChannels(); ++channel)
150 | info.buffer->copyFrom (channel, info.startSample + size1, buffer.getReadPointer (channel, start2), size2);
151 | finishedRead (size1 + size2);
152 | }
153 |
154 | /*< Returns the number of channels of the underlying buffer */
155 | int getNumChannels () const {
156 | return buffer.getNumChannels();
157 | }
158 |
159 | /*< Clears all samples and sets the FIFO state to empty */
160 | void clear () {
161 | buffer.clear ();
162 | reset();
163 | }
164 |
165 | private:
166 | /*< The actual audio buffer */
167 | juce::AudioBuffer buffer;
168 | };
169 |
170 |
171 |
172 |
173 | #endif /* FSPRO_AUDIOBASICS_AUDIOBUFFERFIFO_H_INCLUDED */
174 |
175 |
--------------------------------------------------------------------------------
/modules/filmstro_audiohelpers/filmstro_audiohelpers_AudioProcessorPlayerSource.h:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 | Copyright (c) 2017, Filmstro Ltd. - Daniel Walz
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without modification,
7 | are permitted provided that the following conditions are met:
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 | 3. Neither the name of the copyright holder nor the names of its contributors
14 | may be used to endorse or promote products derived from this software without
15 | specific prior written permission.
16 |
17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
26 | OF THE POSSIBILITY OF SUCH DAMAGE.
27 | ==============================================================================
28 | \class AudioProcessorPlayerSource
29 | \file filmstro_audiobasics_AudioProcessorPlayerSource.h
30 | \brief An AudioSource to playback audioProcessors
31 |
32 | \author Daniel Walz / Filmstro Ltd.
33 | \date December 15th 2016
34 |
35 | \description An AudioSource playing back an AudioProcessor
36 |
37 | ==============================================================================
38 | */
39 |
40 |
41 | #ifndef filmstro_audiobasics_AudioProcessorPlayerSource_h
42 | #define filmstro_audiobasics_AudioProcessorPlayerSource_h
43 |
44 | class AudioProcessorPlayerSource : public juce::AudioSource
45 | {
46 | public:
47 | AudioProcessorPlayerSource (juce::AudioProcessor* proc, const int channels = 2,
48 | const bool deleteProcessor = true)
49 | : processor (proc, deleteProcessor),
50 | numChannels (channels),
51 | fifo (channels, 4096)
52 | {
53 |
54 | }
55 |
56 | virtual ~AudioProcessorPlayerSource ()
57 | {
58 | }
59 |
60 | void prepareToPlay (int samplesPerBlockExpected, double sampleRate) override
61 | {
62 | buffer.setSize (numChannels, samplesPerBlockExpected);
63 | if (processor) {
64 | buffer.setSize (numChannels, samplesPerBlockExpected);
65 | processor->prepareToPlay (sampleRate, samplesPerBlockExpected);
66 | }
67 | }
68 |
69 | void releaseResources () override
70 | {
71 | if (processor) {
72 | processor->releaseResources ();
73 | }
74 | }
75 |
76 | void setProcessor (juce::AudioProcessor* proc, const bool deleteProcessor)
77 | {
78 | fifo.clear ();
79 | processor.set (proc, deleteProcessor);
80 | }
81 |
82 | juce::AudioProcessor* getCurrentProcessor () const
83 | {
84 | return processor;
85 | }
86 |
87 | void getNextAudioBlock (const juce::AudioSourceChannelInfo &bufferToFill) override
88 | {
89 | if (processor) {
90 | juce::MidiBuffer midiBuffer;
91 | while (fifo.getNumReady() < bufferToFill.numSamples) {
92 | processor->processBlock (buffer, midiBuffer);
93 | fifo.addToFifo (buffer);
94 | }
95 | const int ready = fifo.getNumReady ();
96 | if (ready >= bufferToFill.numSamples)
97 | {
98 | fifo.readFromFifo (bufferToFill);
99 | }
100 | else if (ready > 0) {
101 | fifo.readFromFifo (bufferToFill, ready);
102 | bufferToFill.buffer->clear (bufferToFill.startSample + ready, bufferToFill.numSamples - ready);
103 | }
104 | else {
105 | bufferToFill.clearActiveBufferRegion ();
106 | }
107 | }
108 | else {
109 | bufferToFill.clearActiveBufferRegion();
110 | }
111 | }
112 |
113 | private:
114 |
115 | juce::OptionalScopedPointer processor;
116 |
117 | int numChannels;
118 |
119 | // buffer some audio data
120 | AudioBufferFIFO fifo;
121 |
122 | // processor buffer
123 | juce::AudioBuffer buffer;
124 | };
125 |
126 |
127 |
128 | #endif /* filmstro_audiobasics_AudioProcessorPlayerSource_h */
129 |
--------------------------------------------------------------------------------
/modules/filmstro_audiohelpers/filmstro_audiohelpers_OutputSourcePlayer.h:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 | Copyright (c) 2017, Filmstro Ltd. - Daniel Walz
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without modification,
7 | are permitted provided that the following conditions are met:
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 | 3. Neither the name of the copyright holder nor the names of its contributors
14 | may be used to endorse or promote products derived from this software without
15 | specific prior written permission.
16 |
17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
26 | OF THE POSSIBILITY OF SUCH DAMAGE.
27 | ==============================================================================
28 | \class OutputSourcePlayer
29 | \file filmstro_audiobasics_OutputSourcePlayer.h
30 | \brief An AudioSourcePlayer which handles changes of the sample rate
31 |
32 | \author Daniel Walz / Filmstro Ltd.
33 | \date December 19th 2016
34 |
35 | \description An AudioSourcePlayer which handles changes of the sample rate
36 |
37 | ==============================================================================
38 | */
39 |
40 |
41 | #ifndef filmstro_audiobasics_OutputSourcePlayer_h
42 | #define filmstro_audiobasics_OutputSourcePlayer_h
43 |
44 | /**
45 | This class provides an AudioSourcePlayer, which will adapt its resampler whenever
46 | the device changes the sampling rate
47 | */
48 | class OutputSourcePlayer : public juce::AudioSourcePlayer
49 | {
50 | public:
51 | /**
52 | Constructs an OutputSourcePlayer. This makes the processing independent from the devices playback rate.
53 | \param sampleRate is the sample rate the playing AudioSource would expect
54 | \param channels is the number of channels for the resampler to provide. Defaults to 2 (stereo)
55 | */
56 | OutputSourcePlayer (double sampleRate, int channels=2)
57 | : internalSampleRate (sampleRate),
58 | deviceSampleRate (0.0),
59 | numChannels (channels),
60 | outputDevice (nullptr)
61 | {
62 |
63 | }
64 |
65 | /**
66 | Set or replace the source of the AudioSourcePlayer
67 | */
68 | void setSource (juce::AudioSource* newSource)
69 | {
70 | const juce::ScopedLock sl (readLock);
71 | juce::AudioSourcePlayer::setSource (newSource);
72 | }
73 |
74 | /**
75 | Callback from the AudioIODevice. This drives the playback of the AudioSource
76 | */
77 | void audioDeviceIOCallback (const float **inputChannelData, int totalNumInputChannels,
78 | float **outputChannelData, int totalNumOutputChannels,
79 | int numSamples) override
80 | {
81 | if (getCurrentSource()) {
82 | const juce::ScopedLock sl (readLock);
83 |
84 | if (outputDevice != nullptr) {
85 | if (fabs (deviceSampleRate - outputDevice->getCurrentSampleRate ()) > 1.0) {
86 | deviceSampleRate = outputDevice->getCurrentSampleRate();
87 | resampler->setResamplingRatio (deviceSampleRate != 0 ?
88 | internalSampleRate / deviceSampleRate :
89 | 1.0);
90 | resampler->flushBuffers ();
91 | }
92 | }
93 | juce::AudioBuffer buffer (outputChannelData,
94 | totalNumOutputChannels,
95 | numSamples);
96 | juce::AudioSourceChannelInfo bufferToFill (&buffer, 0, numSamples);
97 | resampler->getNextAudioBlock (bufferToFill);
98 | }
99 | else {
100 | juce::AudioSourcePlayer::audioDeviceIOCallback (inputChannelData,
101 | totalNumInputChannels,
102 | outputChannelData,
103 | totalNumOutputChannels,
104 | numSamples);
105 | }
106 | }
107 |
108 | /**
109 | callback when the device wants to start using the AudioDeviceIOCallback
110 | */
111 | void audioDeviceAboutToStart (juce::AudioIODevice *device) override
112 | {
113 | outputDevice = device;
114 | resampler = new juce::ResamplingAudioSource (getCurrentSource(), false);
115 | resampler->prepareToPlay (device->getCurrentBufferSizeSamples(),
116 | device->getCurrentSampleRate());
117 | juce::AudioSourcePlayer::audioDeviceAboutToStart (device);
118 | }
119 |
120 | /**
121 | Callback when the AudioIODevice just stopped using the AudioDeviceIOCallback
122 | */
123 | void audioDeviceStopped () override
124 | {
125 | juce::AudioSourcePlayer::audioDeviceStopped();
126 | resampler = nullptr;
127 | outputDevice = nullptr;
128 | }
129 |
130 |
131 |
132 | private:
133 | double internalSampleRate;
134 |
135 | double deviceSampleRate;
136 |
137 | int numChannels;
138 |
139 | juce::AudioIODevice* outputDevice;
140 |
141 | juce::ScopedPointer resampler;
142 |
143 | juce::CriticalSection readLock;
144 | };
145 |
146 |
147 | #endif /* filmstro_audiobasics_OutputSourcePlayer_h */
148 |
--------------------------------------------------------------------------------
/modules/filmstro_audiohelpers/filmstro_audiohelpers_SharedFormatManager.h:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 | Copyright (c) 2017, Filmstro Ltd. - Daniel Walz
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without modification,
7 | are permitted provided that the following conditions are met:
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 | 3. Neither the name of the copyright holder nor the names of its contributors
14 | may be used to endorse or promote products derived from this software without
15 | specific prior written permission.
16 |
17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
26 | OF THE POSSIBILITY OF SUCH DAMAGE.
27 | ==============================================================================
28 | \class SharedFormatManager
29 | \file filmstro_audiobasics_SharedFormatManager.h
30 | \brief A FormatManager that registers audio formats by default
31 |
32 | \author Daniel Walz / Filmstro Ltd.
33 | \date October 10th 2016
34 |
35 | \description A FormatManager that registers audio formats by default, so it
36 | can be used as SharedResourcePointer
37 |
38 | ==============================================================================
39 | */
40 |
41 | #ifndef filmstro_audiobasics_SharedFormatManager_h
42 | #define filmstro_audiobasics_SharedFormatManager_h
43 |
44 | /**
45 | This is a AudioFormatManager that registers all basic formats when created.
46 | Made to be used with JUCE's SharedResourcePointer
47 | */
48 | class SharedFormatManager : public juce::AudioFormatManager
49 | {
50 | public:
51 | SharedFormatManager()
52 | {
53 | registerBasicFormats();
54 | }
55 | };
56 |
57 |
58 | #endif /* filmstro_audiobasics_SharedFormatManager_h */
59 |
--------------------------------------------------------------------------------
/modules/filmstro_ffmpeg/filmstro_ffmpeg.h:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 |
4 | Copyright (c) 2017, Daniel Walz
5 | All rights reserved.
6 |
7 | Redistribution and use in source and binary forms, with or without modification,
8 | are permitted provided that the following conditions are met:
9 |
10 | 1. Redistributions of source code must retain the above copyright notice, this
11 | list of conditions and the following disclaimer.
12 |
13 | 2. Redistributions in binary form must reproduce the above copyright notice,
14 | this list of conditions and the following disclaimer in the documentation
15 | and/or other materials provided with the distribution.
16 |
17 | 3. Neither the name of the copyright holder nor the names of its contributors
18 | may be used to endorse or promote products derived from this software without
19 | specific prior written permission.
20 |
21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
29 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30 | OF THE POSSIBILITY OF SUCH DAMAGE.
31 |
32 | ==============================================================================
33 |
34 | BEGIN_JUCE_MODULE_DECLARATION
35 |
36 | ID: filmstro_ffmpeg
37 | vendor: Filmstro Ltd.
38 | version: 0.9.0
39 | name: FFmpeg wrapping classes for use in JUCE
40 | description: Provides classes to read audio streams from video files or to
41 | mux audio into an existing video
42 | dependencies: juce_audio_basics, juce_audio_formats, juce_core, filmstro_audiohelpers
43 | website: http://www.filmstro.com/
44 | license: BSD V2 3-clause
45 |
46 | END_JUCE_MODULE_DECLARATION
47 |
48 | ==============================================================================
49 | */
50 |
51 |
52 | #ifndef FSPRO_FFMPEG_INCLUDED_H
53 | #define FSPRO_FFMPEG_INCLUDED_H
54 |
55 |
56 | #include
57 | #include
58 | #include
59 | #include
60 | #include "filmstro_audiohelpers/filmstro_audiohelpers_AudioBufferFIFO.h"
61 |
62 | #ifndef FILMSTRO_USE_FFMPEG
63 | #define FILMSTRO_USE_FFMPEG 1
64 | #endif
65 |
66 | #ifdef __cplusplus
67 | extern "C" {
68 | #endif
69 |
70 | #include
71 | #include
72 | #include
73 | #include
74 | #include
75 | #include
76 | #include
77 |
78 | #ifdef __cplusplus
79 | }
80 | #endif
81 |
82 | #include "filmstro_ffmpeg_FFmpegVideoListener.h"
83 | #include "filmstro_ffmpeg_FFmpegVideoScaler.h"
84 | #include "filmstro_ffmpeg_FFmpegVideoReader.h"
85 | #include "filmstro_ffmpeg_FFmpegVideoWriter.h"
86 | #include "filmstro_ffmpeg_FFmpegVideoComponent.h"
87 |
88 |
89 | #endif /* FSPRO_FFMPEG_INCLUDED_H */
90 |
--------------------------------------------------------------------------------
/modules/filmstro_ffmpeg/filmstro_ffmpeg_FFmpegVideoComponent.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 | Copyright (c) 2017, Filmstro Ltd. - Daniel Walz
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without modification,
7 | are permitted provided that the following conditions are met:
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 | 3. Neither the name of the copyright holder nor the names of its contributors
14 | may be used to endorse or promote products derived from this software without
15 | specific prior written permission.
16 |
17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
26 | OF THE POSSIBILITY OF SUCH DAMAGE.
27 | ==============================================================================
28 | \class FFmpegVideoComponent
29 | \file filmstro_ffmpeg_FFmpegVideoComponent.cpp
30 | \brief A component to view a video decoded by FFmpeg
31 |
32 | \author Daniel Walz @ filmstro.com
33 | \date August 31st 2016
34 |
35 | \description This component will display the movie in the gui.
36 | It has a FFmpegVideoSource, which will send changeMessages when
37 | a new Video frame arrived in the stream to be displayed.
38 |
39 | ==============================================================================
40 |
41 | Ripped from example:
42 | http://ffmpeg.org/doxygen/trunk/demuxing_decoding_8c-example.html
43 |
44 | ==============================================================================
45 | */
46 |
47 |
48 | #include "../JuceLibraryCode/JuceHeader.h"
49 |
50 | // ==============================================================================
51 | // FFmpegVideoComponent
52 | // ==============================================================================
53 |
54 | FFmpegVideoComponent::FFmpegVideoComponent ()
55 | : currentFrame (nullptr),
56 | dirty (true)
57 | {
58 | setOpaque (true);
59 | startTimerHz (80);
60 | }
61 |
62 | FFmpegVideoComponent::~FFmpegVideoComponent ()
63 | {
64 | }
65 |
66 | void FFmpegVideoComponent::resized ()
67 | {
68 | if (videoSource) {
69 | double aspectRatio = videoSource->getVideoAspectRatio() * videoSource->getVideoPixelAspect();
70 | if (aspectRatio > 0) {
71 | double w = getWidth();
72 | double h = getHeight();
73 | if (w / h > aspectRatio) {
74 | w = h * aspectRatio;
75 | }
76 | else {
77 | h = w / aspectRatio;
78 | }
79 | frameBuffer = Image (Image::PixelFormat::ARGB, static_cast (w), static_cast (h), true);
80 | videoScaler.setupScaler (videoSource->getVideoWidth(),
81 | videoSource->getVideoHeight(),
82 | videoSource->getPixelFormat(),
83 | frameBuffer.getWidth(),
84 | frameBuffer.getHeight (),
85 | AV_PIX_FMT_BGR0);
86 | }
87 | }
88 | }
89 |
90 | void FFmpegVideoComponent::timerCallback ()
91 | {
92 | if (dirty) {
93 | dirty = false;
94 | repaint ();
95 | }
96 | }
97 |
98 | void FFmpegVideoComponent::paint (juce::Graphics& g)
99 | {
100 | g.fillAll (Colours::black);
101 | if (videoSource && currentFrame && frameBuffer.isValid()) {
102 | videoScaler.convertFrameToImage (frameBuffer, currentFrame);
103 | g.drawImageAt (frameBuffer,
104 | (getWidth() - frameBuffer.getWidth()) * 0.5,
105 | (getHeight() - frameBuffer.getHeight()) * 0.5);
106 | }
107 | else {
108 | g.drawFittedText ("No VideoSource connected", getLocalBounds(), juce::Justification::centred, 1);
109 | }
110 | }
111 |
112 | /** callback from FFmpegVideoReader to display a new frame */
113 | void FFmpegVideoComponent::displayNewFrame (const AVFrame* frame)
114 | {
115 | if (dirty) {
116 | DBG ("Frame not painted: " + String (av_frame_get_best_effort_timestamp (currentFrame)));
117 | }
118 | currentFrame = frame;
119 | dirty = true;
120 | }
121 |
122 | /** This is called whenever the size changed, so a framebuffer can be resized */
123 | void FFmpegVideoComponent::videoSizeChanged (const int width, const int height, const AVPixelFormat format)
124 | {
125 | resized();
126 | dirty = true;
127 | }
128 |
129 | void FFmpegVideoComponent::setVideoReader (FFmpegVideoReader* source)
130 | {
131 | if (videoSource)
132 | videoSource->removeVideoListener (this);
133 |
134 | videoSource = source;
135 |
136 | if (videoSource)
137 | videoSource->addVideoListener(this);
138 |
139 | dirty = true;
140 | }
141 |
142 | FFmpegVideoReader* FFmpegVideoComponent::getVideoReader () const
143 | {
144 | return videoSource;
145 | }
146 |
--------------------------------------------------------------------------------
/modules/filmstro_ffmpeg/filmstro_ffmpeg_FFmpegVideoComponent.h:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 | Copyright (c) 2017, Filmstro Ltd. - Daniel Walz
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without modification,
7 | are permitted provided that the following conditions are met:
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 | 3. Neither the name of the copyright holder nor the names of its contributors
14 | may be used to endorse or promote products derived from this software without
15 | specific prior written permission.
16 |
17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
26 | OF THE POSSIBILITY OF SUCH DAMAGE.
27 | ==============================================================================
28 | \class FFmpegVideoComponent
29 | \file filmstro_ffmpeg_FFmpegVideoComponent.h
30 | \brief A component to view a video decoded by FFmpeg
31 |
32 | \author Daniel Walz @ filmstro.com
33 | \date August 31st 2016
34 |
35 | \description This component will display the movie in the gui.
36 | It has a FFmpegVideoSource, which will send changeMessages when
37 | a new Video frame arrived in the stream to be displayed.
38 |
39 | ==============================================================================
40 | */
41 |
42 |
43 | #ifndef FILMSTRO_FFMPEG_FFMPEGVIDEOCOMPONENT_H_INCLUDED
44 | #define FILMSTRO_FFMPEG_FFMPEGVIDEOCOMPONENT_H_INCLUDED
45 |
46 | class FFmpegVideoSource;
47 |
48 | /**
49 | \class FFmpegVideoComponent
50 | \description Component to display a video read by FFmpegVideoReader
51 | */
52 | class FFmpegVideoComponent : public juce::Component,
53 | public juce::Timer,
54 | public FFmpegVideoListener
55 | {
56 | public:
57 | FFmpegVideoComponent ();
58 | virtual ~FFmpegVideoComponent ();
59 |
60 | /** Callback when the component is resized */
61 | void resized () override;
62 |
63 | void paint (juce::Graphics& g) override;
64 |
65 | /** triggers repaint on message thread */
66 | void timerCallback () override;
67 |
68 | /** callback from FFmpegVideoReader to display a new frame */
69 | void displayNewFrame (const AVFrame*) override;
70 |
71 | /** This is called whenever the size changed, so a framebuffer can be resized */
72 | void videoSizeChanged (const int width, const int height, const AVPixelFormat) override;
73 |
74 | /** Set a video source for the component */
75 | void setVideoReader (FFmpegVideoReader* source);
76 |
77 | /** Get the video source for the component */
78 | FFmpegVideoReader* getVideoReader () const;
79 |
80 | private:
81 | /** Format the timecode in seconds */
82 | juce::String formatTimeCode (const double tc);
83 |
84 | /** Reference to the FFmpegVideoReader to provide video frames */
85 | juce::WeakReference videoSource;
86 |
87 | const AVFrame* currentFrame;
88 |
89 | juce::Image frameBuffer;
90 |
91 | FFmpegVideoScaler videoScaler;
92 |
93 | bool dirty;
94 |
95 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FFmpegVideoComponent)
96 | };
97 |
98 | #endif /* FILMSTRO_FFMPEG_FFMPEGVIDEOCOMPONENT_H_INCLUDED */
99 |
100 |
--------------------------------------------------------------------------------
/modules/filmstro_ffmpeg/filmstro_ffmpeg_FFmpegVideoListener.h:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 | Copyright (c) 2017, Filmstro Ltd. - Daniel Walz
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without modification,
7 | are permitted provided that the following conditions are met:
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 | 3. Neither the name of the copyright holder nor the names of its contributors
14 | may be used to endorse or promote products derived from this software without
15 | specific prior written permission.
16 |
17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
26 | OF THE POSSIBILITY OF SUCH DAMAGE.
27 | ==============================================================================
28 | \class FFmpegVideoListener
29 | \file filmstro_ffmpeg_FFmpegVideoListener.h
30 | \brief Interface for video related callbacks from FFmpeg
31 |
32 | \author Daniel Walz @ filmstro.com
33 | \date January 25th 2017
34 |
35 | \description This is an interface for objects, that want to receive video frames
36 |
37 | ==============================================================================
38 | */
39 |
40 |
41 | #ifndef FILMSTRO_FFMPEG_FFMPEGVIDEOLISTENER_H_INCLUDED
42 | #define FILMSTRO_FFMPEG_FFMPEGVIDEOLISTENER_H_INCLUDED
43 |
44 | class FFmpegVideoListener {
45 |
46 | public:
47 |
48 | FFmpegVideoListener() {}
49 |
50 | virtual ~FFmpegVideoListener() {}
51 |
52 | /** This will notify about advancing the presentation timestamp */
53 | virtual void presentationTimestampChanged (const double) {}
54 |
55 | /** This is called whenever the size changed, so a framebuffer can be resized */
56 | virtual void videoSizeChanged (const int width, const int height, const AVPixelFormat) {}
57 |
58 | /** This is called when a frame is read from the video stream. It will be
59 | called in the correct sequence, but not synchronised to the audio stream.
60 | You can use that for transcoding a video stream */
61 | virtual void readRawFrame (const AVFrame*) {}
62 |
63 | /** This is called when a frame is due to be displayed according to audio's
64 | presentation timestamp PTS as raw frame */
65 | virtual void displayNewFrame (const AVFrame*) {}
66 |
67 | /** This is called when the video source file has changed */
68 | virtual void videoFileChanged (const juce::File& newSource) {}
69 |
70 | };
71 |
72 | #endif /* FILMSTRO_FFMPEG_FFMPEGVIDEOLISTENER_H_INCLUDED */
73 |
--------------------------------------------------------------------------------
/modules/filmstro_ffmpeg/filmstro_ffmpeg_FFmpegVideoReader.h:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 | Copyright (c) 2017, Filmstro Ltd. - Daniel Walz
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without modification,
7 | are permitted provided that the following conditions are met:
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 | 3. Neither the name of the copyright holder nor the names of its contributors
14 | may be used to endorse or promote products derived from this software without
15 | specific prior written permission.
16 |
17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
26 | OF THE POSSIBILITY OF SUCH DAMAGE.
27 | ==============================================================================
28 | \class FFmpegVideoReader
29 | \file filmstro_ffmpeg_FFmpegVideoReader.h
30 | \brief A component to view a video decoded by FFmpeg
31 |
32 | \author Daniel Walz @ filmstro.com
33 | \date August 31st 2016
34 |
35 | \description This class will read a video file using ffmpeg
36 |
37 | ==============================================================================
38 | */
39 |
40 |
41 | #ifndef FILMSTRO_FFMPEG_FFMPEGVIDEOREADER_H_INCLUDED
42 | #define FILMSTRO_FFMPEG_FFMPEGVIDEOREADER_H_INCLUDED
43 |
44 | #include
45 |
46 | /**
47 | \class FFmpegVideoReader
48 | \description Reads a ffmpeg video file
49 |
50 | The FFmpegVideoReader opens a ffmpeg stream for reading. It acts as regular
51 | juce::AudioSource and can be played like that. Additionally it provides a
52 | FFmpegVideoSource which can be used to display the video frames or to write
53 | the file back using a FFmpegVideoWriter.
54 | */
55 | class FFmpegVideoReader : public juce::PositionableAudioSource
56 | {
57 | public:
58 |
59 | /** Constructs a FFmpegVideoReader. Because usually audio and video frames may
60 | be in arbitrary order, the reader provides a FIFO for audio samples and a FIFO
61 | for video frames. */
62 | FFmpegVideoReader (const int audioFifoSize=192000, const int videoFifoSize=20);
63 | virtual ~FFmpegVideoReader();
64 |
65 | // ==============================================================================
66 | // video decoder thread
67 | // ==============================================================================
68 | /**
69 | \class FFmpegVideoReader::DecoderThread
70 | \description class for FFmpegReader to decode audio and images asynchronously
71 | This is to keep the audio thread as fast as possible
72 | */
73 | class DecoderThread : public juce::Thread
74 | {
75 | public:
76 | DecoderThread (AudioBufferFIFO& fifo, const int videoFifoSize);
77 |
78 | virtual ~DecoderThread ();
79 |
80 | bool loadMovieFile (const juce::File& inputFile);
81 |
82 | void closeMovieFile ();
83 |
84 | void addVideoListener (FFmpegVideoListener* listener);
85 |
86 | void removeVideoListener (FFmpegVideoListener* listener);
87 |
88 | /** working loop */
89 | void run() override;
90 |
91 | /** set the currently played PTS according to the audio stream */
92 | void setCurrentPTS (const double pts, bool seek = false);
93 |
94 | /** returns the presentation timestamp the video is synchronised to */
95 | double getCurrentPTS () const;
96 |
97 | /** get the width of the video images according to decoder */
98 | int getVideoWidth () const;
99 |
100 | /** get the height of the video images according to decoder */
101 | int getVideoHeight () const;
102 |
103 | /** get the pixel format of the video images according to decoder,
104 | will be converted to BGR0 to be displayed as juce::Image */
105 | enum AVPixelFormat getPixelFormat () const;
106 |
107 | /** This will return the aspect ratio of each pixel */
108 | double getPixelAspect () const;
109 |
110 | enum AVSampleFormat getSampleFormat () const;
111 |
112 | /** Return the framerate. If framerate in the decoder context is not set,
113 | this will return the timebase of the video stream. */
114 | double getFramesPerSecond () const;
115 |
116 | /** This will return the time_base from the video stream */
117 | AVRational getVideoTimeBase () const;
118 |
119 | /** Give access to the context to set up writers */
120 | AVFormatContext* getVideoReaderContext();
121 |
122 | double getSampleRate () const;
123 |
124 | double getDuration () const;
125 |
126 | int getNumChannels () const;
127 |
128 | AVCodecContext* getVideoContext () const;
129 | AVCodecContext* getAudioContext () const;
130 | AVCodecContext* getSubtitleContext () const;
131 |
132 | private:
133 |
134 | int openCodecContext (AVCodecContext** decoderContext,
135 | enum AVMediaType type,
136 | bool refCounted);
137 |
138 | /** Returns the number of added samples to the audio FIFO */
139 | int decodeAudioPacket (AVPacket packet);
140 |
141 | /** Returns the presentation timecode PTS of the decoded frame */
142 | double decodeVideoPacket (AVPacket packet);
143 |
144 |
145 | // ==============================================================================
146 |
147 |
148 | /** has access to the audio sources fifo to fill it */
149 | AudioBufferFIFO& audioFifo;
150 |
151 | juce::WaitableEvent waitForPacket;
152 |
153 | /** vector of PTS -> AVFrame tuples */
154 | std::vector > videoFrames;
155 | std::atomic videoFifoRead;
156 | std::atomic videoFifoWrite;
157 |
158 | AVFormatContext* formatContext;
159 | AVCodecContext* videoContext;
160 | AVCodecContext* audioContext;
161 | AVCodecContext* subtitleContext;
162 | SwrContext* audioConverterContext;
163 |
164 | int videoStreamIdx;
165 | int audioStreamIdx;
166 | int subtitleStreamIdx;
167 |
168 | AVFrame* audioFrame;
169 | juce::AudioBuffer audioConvertBuffer;
170 |
171 | std::atomic currentPTS;
172 |
173 | juce::ListenerList videoListeners;
174 |
175 | /** Buffer for reading */
176 | juce::AudioBuffer buffer;
177 |
178 | };
179 |
180 | // ==============================================================================
181 | // video methods
182 | // ==============================================================================
183 |
184 | bool loadMovieFile (const juce::File& inputFile);
185 |
186 | void closeMovieFile ();
187 |
188 | /** Returns the currently opened video file */
189 | juce::File getVideoFileName () const;
190 |
191 | /** Return the framerate. If framerate in the decoder context is not set,
192 | this will return the timebase of the video stream. */
193 | double getFramesPerSecond () const;
194 |
195 | /** Get current presentation timecode according to audio stream */
196 | double getCurrentTimeStamp() const;
197 |
198 | /** returns the duration of the video in seconds according to the container context */
199 | double getVideoDuration () const;
200 |
201 | /** returns the sampling rate as specified in the video file. This can be different
202 | from the samplingrate the prepareToPlay was called with.
203 | The FFmpegVideoReader will not resample. */
204 | int getVideoSamplingRate () const;
205 |
206 | /** returns the number of audio channels in the video file. Make sure you call
207 | getNextAudioBuffer with the same number of channels */
208 | int getVideoChannels () const;
209 |
210 | /** returns the audio sample format in the video file.
211 | The FFmpegVideoReader will convert into discrete channels of float values */
212 | enum AVSampleFormat getSampleFormat () const;
213 |
214 | /** add a listener to receive video frames for displaying and to get timestamp
215 | notifications. The video frames will happen synchronously to getNextAudioBlock */
216 | void addVideoListener (FFmpegVideoListener* listener);
217 |
218 | /** remove a video listener */
219 | void removeVideoListener (FFmpegVideoListener* listener);
220 |
221 | double getLastVideoPTS () const;
222 |
223 | /** get the width of the video images according to decoder */
224 | int getVideoWidth () const;
225 |
226 | /** get the height of the video images according to decoder */
227 | int getVideoHeight () const;
228 |
229 | /** returns the aspect ratio video frame */
230 | double getVideoAspectRatio () const;
231 |
232 | /** This will return the aspect ratio of each pixel */
233 | double getVideoPixelAspect () const;
234 |
235 | /** get the pixel format of the video images according to decoder,
236 | will be converted to BGR0 to be displayed as juce::Image */
237 | enum AVPixelFormat getPixelFormat () const;
238 |
239 | /** This will return the time_base from the video stream */
240 | AVRational getVideoTimeBase () const;
241 |
242 | static juce::String formatTimeCode (const double tc);
243 |
244 |
245 | // ==============================================================================
246 | // from PositionableAudioSource
247 | // ==============================================================================
248 |
249 | void prepareToPlay (int samplesPerBlockExpected, double sampleRate) override;
250 |
251 | void releaseResources () override;
252 |
253 | /** decodes packets to fill the audioFifo. If a video packet is found it will be forwarded to VideoDecoderThread */
254 | void getNextAudioBlock (const juce::AudioSourceChannelInfo &bufferToFill) override;
255 |
256 | /** Wait until the decoder thread has finished enough data. This is needed for non-realtime processing. */
257 | bool waitForNextAudioBlockReady (const juce::AudioSourceChannelInfo &bufferToFill, const int msecs) const;
258 |
259 | /** Seeks in the stream */
260 | void setNextReadPosition (juce::int64 newPosition) override;
261 |
262 | /** Returns the sample count of the next sample to be returned by getNextAudioBlock */
263 | juce::int64 getNextReadPosition () const override;
264 |
265 | /** Returns the total length in samples. May not be accurate, because it uses ffmpegs
266 | duration property multiplied with the samplerate */
267 | juce::int64 getTotalLength () const override;
268 |
269 | /** Returns true if this source is actually playing in a loop. */
270 | bool isLooping() const override;
271 |
272 | /** Tells the source whether you'd like it to play in a loop. */
273 | void setLooping (bool shouldLoop) override;
274 |
275 | // ==============================================================================
276 | // FFmpeg low level
277 | // ==============================================================================
278 |
279 | AVCodecContext* getVideoContext () const;
280 | AVCodecContext* getAudioContext () const;
281 | AVCodecContext* getSubtitleContext () const;
282 |
283 |
284 | // ==============================================================================
285 | private:
286 |
287 | juce::File videoFileName;
288 |
289 | bool fileReadyToRead;
290 |
291 | bool looping;
292 |
293 | int sampleRate;
294 |
295 | double framesPerSec;
296 |
297 | double resampleFactor;
298 |
299 | double currentTimeStamp;
300 |
301 | juce::int64 nextReadPos;
302 |
303 | AudioBufferFIFO audioFifo;
304 |
305 | DecoderThread decoder;
306 |
307 | // use WeakReference so that removing a source doesn't lead to disaster
308 | juce::WeakReference::Master masterReference;
309 | friend class juce::WeakReference;
310 |
311 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FFmpegVideoReader)
312 | };
313 |
314 | #endif /* FILMSTRO_FFMPEG_FFMPEGVIDEOREADER_H_INCLUDED */
315 |
316 |
--------------------------------------------------------------------------------
/modules/filmstro_ffmpeg/filmstro_ffmpeg_FFmpegVideoScaler.h:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 | Copyright (c) 2017, Filmstro Ltd. - Daniel Walz
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without modification,
7 | are permitted provided that the following conditions are met:
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 | 3. Neither the name of the copyright holder nor the names of its contributors
14 | may be used to endorse or promote products derived from this software without
15 | specific prior written permission.
16 |
17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
26 | OF THE POSSIBILITY OF SUCH DAMAGE.
27 | ==============================================================================
28 | \class FFmpegVideoScaler
29 | \file filmstro_ffmpeg_FFmpegVideoScaler.h
30 | \brief Converts and scales FFmpeg frames into juce format
31 |
32 | \author Daniel Walz @ filmstro.com
33 | \date January 25th 2017
34 |
35 | \description Converts and scales FFmpeg frames into juce format
36 |
37 | ==============================================================================
38 | */
39 |
40 |
41 | #ifndef FILMSTRO_FFMPEG_FFMPEGVIDEOSCALER_H_INCLUDED
42 | #define FILMSTRO_FFMPEG_FFMPEGVIDEOSCALER_H_INCLUDED
43 |
44 | class FFmpegVideoScaler {
45 | public:
46 | /** Creates a scaler object. It does nothing before you call setupScaler */
47 | FFmpegVideoScaler () : scalerContext (nullptr) {}
48 |
49 | ~FFmpegVideoScaler ()
50 | {
51 | if (scalerContext)
52 | sws_freeContext (scalerContext);
53 | }
54 |
55 | /** Setup a scaler to scale video frames and to convert pixel formats */
56 | void setupScaler (const int in_width, const int in_height, const AVPixelFormat in_format,
57 | const int out_width, const int out_height, const AVPixelFormat out_format)
58 | {
59 | if (scalerContext) {
60 | sws_freeContext (scalerContext);
61 | scalerContext = nullptr;
62 | }
63 |
64 | const AVPixFmtDescriptor* in_descriptor = av_pix_fmt_desc_get (in_format);
65 | if (!in_descriptor) {
66 | DBG ("No description for input pixel format");
67 | return;
68 | }
69 | const int in_bitsPerPixel = av_get_padded_bits_per_pixel (in_descriptor);
70 | for (int i=0; i < 4; ++i)
71 | inLinesizes [i] = i < in_descriptor->nb_components ? in_width * in_bitsPerPixel >> 3 : 0;
72 |
73 | const AVPixFmtDescriptor* out_descriptor = av_pix_fmt_desc_get (out_format);
74 | if (!out_descriptor) {
75 | DBG ("No description for output pixel format");
76 | return;
77 | }
78 | const int out_bitsPerPixel = av_get_padded_bits_per_pixel (out_descriptor);
79 | for (int i=0; i < 4; ++i)
80 | outLinesizes [i] = i < out_descriptor->nb_components ? out_width * out_bitsPerPixel >> 3 : 0;
81 |
82 | /* create scaling context */
83 | scalerContext = sws_getContext (in_width, in_height, in_format,
84 | out_width, out_height, out_format,
85 | SWS_BILINEAR, NULL, NULL, NULL);
86 | if (!scalerContext) {
87 | DBG ("Impossible to create scale context for the conversion");
88 | }
89 | }
90 |
91 |
92 | /** takes an AVFrame from ffmpeg and converts it to a JUCE Image. Image is in a format
93 | matching to the platform */
94 | void convertFrameToImage (juce::Image& image, const AVFrame* frame)
95 | {
96 | if (scalerContext) {
97 | juce::Image::BitmapData data (image, 0, 0,
98 | image.getWidth(),
99 | image.getHeight(),
100 | juce::Image::BitmapData::writeOnly);
101 |
102 | uint8_t* destination[4] = {data.data, nullptr, nullptr, nullptr};
103 |
104 | sws_scale (scalerContext,
105 | frame->data,
106 | frame->linesize,
107 | 0,
108 | frame->height,
109 | destination,
110 | outLinesizes);
111 | }
112 | }
113 |
114 |
115 | /** Converts a JUCE Image into a ffmpeg AVFrame to be written into a video stream */
116 | void convertImageToFrame (AVFrame* frame, const juce::Image& image)
117 | {
118 | if (scalerContext) {
119 | juce::Image::BitmapData data (image, 0, 0,
120 | image.getWidth(),
121 | image.getHeight());
122 |
123 | uint8_t* source[4] = {data.data, nullptr, nullptr, nullptr};
124 |
125 | sws_scale (scalerContext,
126 | source,
127 | inLinesizes,
128 | 0,
129 | image.getHeight(),
130 | frame->data,
131 | frame->linesize);
132 | }
133 | }
134 |
135 |
136 | private:
137 | SwsContext* scalerContext;
138 |
139 | int inLinesizes[4];
140 | int outLinesizes[4];
141 |
142 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FFmpegVideoScaler)
143 | };
144 |
145 | #endif /* FILMSTRO_FFMPEG_FFMPEGVIDEOSCALER_H_INCLUDED */
146 |
--------------------------------------------------------------------------------
/modules/filmstro_ffmpeg/filmstro_ffmpeg_FFmpegVideoWriter.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 | Copyright (c) 2017, Filmstro Ltd. - Daniel Walz
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without modification,
7 | are permitted provided that the following conditions are met:
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 | 3. Neither the name of the copyright holder nor the names of its contributors
14 | may be used to endorse or promote products derived from this software without
15 | specific prior written permission.
16 |
17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
26 | OF THE POSSIBILITY OF SUCH DAMAGE.
27 | ==============================================================================
28 | \class FFmpegVideoWriter
29 | \file filmstro_ffmpeg_FFmpegVideoWriter.cpp
30 | \brief A component to write a video stream with ffmpeg
31 |
32 | \author Daniel Walz @ filmstro.com
33 | \date September 19th 2016
34 |
35 | \description Use this writer to write audio frames and video frames in a
36 | video file using ffmpeg
37 | ==============================================================================
38 | */
39 |
40 |
41 | #include "../JuceLibraryCode/JuceHeader.h"
42 |
43 | FFmpegVideoWriter::FFmpegVideoWriter (const juce::String& format)
44 | : audioWritePosition (0),
45 | formatContext (nullptr),
46 | videoContext (nullptr),
47 | audioContext (nullptr),
48 | subtitleContext (nullptr),
49 | videoCodec (AV_CODEC_ID_NONE),
50 | audioCodec (AV_CODEC_ID_NONE),
51 | subtitleCodec (AV_CODEC_ID_NONE),
52 | videoStreamIdx (-1),
53 | audioStreamIdx (-1),
54 | subtitleStreamIdx (-1),
55 | sampleRate (48000),
56 | channelLayout (AV_CH_LAYOUT_STEREO),
57 | videoWidth (0),
58 | videoHeight (0),
59 | pixelFormat (AV_PIX_FMT_NONE),
60 | pixelAspect (av_make_q (1, 1)),
61 | audioFifo (2, 8192)
62 | {
63 | videoTimeBase = av_make_q (1, 24);
64 | audioTimeBase = av_make_q (1, sampleRate);
65 | subtitleTimeBase = av_make_q (1, AV_TIME_BASE);
66 |
67 | av_register_all();
68 | if (format.isNotEmpty()) {
69 | formatContext = avformat_alloc_context();
70 | AVOutputFormat* oformat = av_guess_format (format.toRawUTF8(), nullptr, nullptr);
71 | if (oformat) {
72 | formatContext->oformat = oformat;
73 | }
74 | }
75 | }
76 |
77 | FFmpegVideoWriter::~FFmpegVideoWriter()
78 | {
79 | }
80 |
81 | juce::StringArray FFmpegVideoWriter::getOutputFormatNames ()
82 | {
83 | StringArray names;
84 | AVOutputFormat* format = av_oformat_next (nullptr);
85 | while (format) {
86 | names.add (format->name);
87 | format = av_oformat_next (format);
88 | }
89 | return names;
90 | }
91 |
92 | void FFmpegVideoWriter::setVideoCodec (const AVCodecID codec)
93 | {
94 | videoCodec = codec;
95 | }
96 |
97 | void FFmpegVideoWriter::setAudioCodec (const AVCodecID codec)
98 | {
99 | audioCodec = codec;
100 | }
101 |
102 | void FFmpegVideoWriter::setSubtitleCodec (const AVCodecID codec)
103 | {
104 | subtitleCodec = codec;
105 | }
106 |
107 | void FFmpegVideoWriter::setSampleRate (const int newSampleRate)
108 | {
109 | sampleRate = newSampleRate;
110 | audioTimeBase = av_make_q (1, newSampleRate);
111 | }
112 |
113 | void FFmpegVideoWriter::setVideoSize (const int width, const int height)
114 | {
115 | videoWidth = width;
116 | videoHeight = height;
117 | }
118 |
119 | void FFmpegVideoWriter::setPixelFormat (const AVPixelFormat format)
120 | {
121 | pixelFormat = format;
122 | }
123 |
124 | void FFmpegVideoWriter::setPixelAspect (const int num, const int den)
125 | {
126 | pixelAspect = av_make_q (num, den);
127 | }
128 |
129 | void FFmpegVideoWriter::setTimeBase (AVMediaType type, AVRational timebase)
130 | {
131 | switch (type) {
132 | case AVMEDIA_TYPE_VIDEO:
133 | videoTimeBase = timebase;
134 | break;
135 | case AVMEDIA_TYPE_AUDIO:
136 | audioTimeBase = timebase;
137 | break;
138 | case AVMEDIA_TYPE_SUBTITLE:
139 | subtitleTimeBase = timebase;
140 | break;
141 | default:
142 | break;
143 | }
144 | }
145 |
146 | void FFmpegVideoWriter::copySettingsFromContext (const AVCodecContext* context)
147 | {
148 | if (context) {
149 | if (context->codec_type == AVMEDIA_TYPE_VIDEO) {
150 | videoCodec = context->codec_id;
151 | videoWidth = context->width;
152 | videoHeight = context->height;
153 | pixelFormat = context->pix_fmt;
154 | pixelAspect = context->sample_aspect_ratio;
155 | if (context->framerate.num != 0) {
156 | // preferred way
157 | videoTimeBase = av_inv_q (context->framerate);
158 | }
159 | else if (context->time_base.num > 0) {
160 | // some decoders don't set framerate but might provide a time_base
161 | videoTimeBase = context->time_base;
162 | }
163 | }
164 | else if (context->codec_type == AVMEDIA_TYPE_AUDIO) {
165 | audioCodec = context->codec_id;
166 | channelLayout = context->channel_layout;
167 | // we don't copy audio, it's coming from JUCE so it's gonna be AV_SAMPLE_FMT_FLTP
168 | //sampleRate = context->sample_rate;
169 | }
170 | else if (context->codec_type == AVMEDIA_TYPE_SUBTITLE) {
171 | // FIXME: TODO
172 | }
173 | }
174 | }
175 |
176 | bool FFmpegVideoWriter::openMovieFile (const juce::File& outputFile, const juce::String& format)
177 | {
178 | videoStreamIdx = -1;
179 | if (videoContext) av_free (&videoContext);
180 | audioStreamIdx = -1;
181 | if (audioContext) av_free (&audioContext);
182 | subtitleStreamIdx = -1;
183 | if (subtitleContext) av_free (&subtitleContext);
184 |
185 | audioWritePosition = 0;
186 |
187 | if (formatContext) {
188 | String name (outputFile.getFullPathName ());
189 | memcpy (formatContext->filename, name.toRawUTF8 (), jmin (name.getNumBytesAsUTF8 () + 1, sizeof (formatContext->filename)));
190 | }
191 | else {
192 | if (format.isEmpty())
193 | avformat_alloc_output_context2 (&formatContext, NULL, NULL, outputFile.getFullPathName().toRawUTF8());
194 | else
195 | avformat_alloc_output_context2 (&formatContext, NULL, format.toRawUTF8(), outputFile.getFullPathName().toRawUTF8());
196 | }
197 | if (!formatContext) {
198 | DBG ("Could not open output with format " + format);
199 | return false;
200 | }
201 |
202 | if (videoCodec == AV_CODEC_ID_PROBE) {
203 | videoCodec = av_guess_codec (formatContext->oformat,
204 | nullptr, outputFile.getFullPathName().toRawUTF8(),
205 | nullptr,
206 | AVMEDIA_TYPE_VIDEO);
207 | }
208 | if (audioCodec == AV_CODEC_ID_PROBE) {
209 | audioCodec = av_guess_codec (formatContext->oformat,
210 | nullptr, outputFile.getFullPathName().toRawUTF8(),
211 | nullptr,
212 | AVMEDIA_TYPE_AUDIO);
213 | }
214 | if (subtitleCodec == AV_CODEC_ID_PROBE) {
215 | subtitleCodec = av_guess_codec (formatContext->oformat,
216 | nullptr, outputFile.getFullPathName().toRawUTF8(),
217 | nullptr,
218 | AVMEDIA_TYPE_SUBTITLE);
219 | }
220 |
221 | if (videoCodec > AV_CODEC_ID_NONE) {
222 | AVStream* stream = avformat_new_stream (formatContext, NULL);
223 | if (!stream) {
224 | DBG ("Failed allocating video output stream\n");
225 | }
226 | else {
227 | videoStreamIdx = formatContext->nb_streams - 1;
228 | AVCodec* encoder = avcodec_find_encoder (videoCodec);
229 | if (encoder) {
230 | stream->time_base = videoTimeBase;
231 | videoContext = avcodec_alloc_context3 (encoder);
232 | videoContext->time_base = videoTimeBase;
233 | videoContext->pix_fmt = pixelFormat;
234 | videoContext->sample_aspect_ratio = pixelAspect;
235 | videoContext->codec_type = encoder->type;
236 | videoContext->color_range = AVCOL_RANGE_JPEG;
237 | videoContext->codec_id = videoCodec;
238 | videoContext->width = videoWidth;
239 | videoContext->height = videoHeight;
240 | videoContext->bit_rate = 480000;
241 | videoContext->gop_size = 10;
242 | videoContext->max_b_frames = 1;
243 | avcodec_parameters_from_context (stream->codecpar, videoContext);
244 |
245 | AVDictionary* options = nullptr;
246 |
247 | if (encoder->id == AV_CODEC_ID_H264) {
248 | av_dict_set (&options, "preset", "slow", 0);
249 | av_dict_set (&options, "tune", "film", 0);
250 | av_opt_set (videoContext->priv_data, "profile", "baseline", AV_OPT_SEARCH_CHILDREN);
251 | }
252 |
253 | int ret = avcodec_open2 (videoContext, encoder, &options);
254 | if (ret < 0) {
255 | DBG ("Cannot open video encoder");
256 | videoStreamIdx = -1;
257 | videoCodec = AV_CODEC_ID_NONE;
258 | }
259 | av_dict_free (&options);
260 | }
261 | else {
262 | DBG ("Video encoder not found for " + String (avcodec_get_name (videoCodec)));
263 | }
264 | }
265 | }
266 |
267 | if (audioCodec > AV_CODEC_ID_NONE) {
268 | AVStream* stream = avformat_new_stream (formatContext, NULL);
269 | if (!stream) {
270 | DBG ("Failed allocating audio output stream\n");
271 | }
272 | else {
273 | audioStreamIdx = formatContext->nb_streams - 1;
274 | AVCodec* encoder = avcodec_find_encoder (audioCodec);
275 | if (encoder) {
276 | audioContext = avcodec_alloc_context3 (encoder);
277 | audioContext->time_base = audioTimeBase;
278 | audioContext->sample_rate = audioTimeBase.den;
279 | audioContext->sample_fmt = AV_SAMPLE_FMT_FLTP;
280 | audioContext->channel_layout = channelLayout;
281 | audioContext->channels = av_get_channel_layout_nb_channels (channelLayout);
282 | audioContext->bit_rate = 64000;
283 | audioContext->frame_size = 1024;
284 | audioContext->bits_per_raw_sample = 32;
285 | avcodec_parameters_from_context (stream->codecpar, audioContext);
286 |
287 | int ret = avcodec_open2 (audioContext, encoder, NULL);
288 | if (ret < 0) {
289 | char codecName [256];
290 | av_get_codec_tag_string (codecName, 256, audioCodec);
291 | DBG ("Cannot open audio encoder for format: " + String::fromUTF8 (codecName));
292 | audioStreamIdx = -1;
293 | audioCodec = AV_CODEC_ID_NONE;
294 | }
295 | }
296 | else {
297 | DBG ("Audio encoder not found for " + String (avcodec_get_name (audioCodec)));
298 | }
299 | }
300 | }
301 |
302 | //if (subtitleCodec > AV_CODEC_ID_NONE) {
303 | // // FIXME: TODO
304 | //}
305 |
306 | av_dump_format (formatContext, 0, outputFile.getFullPathName().toRawUTF8(), 1);
307 |
308 | if (!(formatContext->oformat->flags & AVFMT_NOFILE)) {
309 | if (avio_open (&formatContext->pb, outputFile.getFullPathName().toRawUTF8(), AVIO_FLAG_WRITE) < 0) {
310 | DBG ("Could not open output file '" + outputFile.getFullPathName() + "'");
311 | closeContexts();
312 | return false;
313 | }
314 | }
315 |
316 | if (formatContext->oformat->flags & AVFMT_GLOBALHEADER) {
317 | if (videoContext) videoContext->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
318 | if (audioContext) audioContext->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
319 | if (subtitleContext) subtitleContext->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
320 | }
321 |
322 | if (!videoContext && !audioContext && !subtitleContext) {
323 | DBG ("No stream provided to encode");
324 | closeContexts();
325 | return false;
326 | }
327 |
328 | if (!(formatContext->oformat->flags & AVFMT_NOFILE)) {
329 | int ret = avio_open(&formatContext->pb, outputFile.getFullPathName().toRawUTF8(), AVIO_FLAG_WRITE);
330 | if (ret < 0) {
331 | av_log(NULL, AV_LOG_ERROR, "Could not open output file '%s'", outputFile.getFullPathName().toRawUTF8());
332 | closeContexts();
333 | return false;
334 | }
335 | }
336 |
337 | int ret = avformat_write_header (formatContext, NULL);
338 | if (ret < 0) {
339 | DBG ("Error occurred when opening output file");
340 | closeContexts();
341 | return false;
342 | }
343 |
344 | return true;
345 | }
346 |
347 | void FFmpegVideoWriter::closeMovieFile ()
348 | {
349 | finishWriting ();
350 | }
351 |
352 | void FFmpegVideoWriter::finishWriting ()
353 | {
354 | if (formatContext) {
355 | AVMediaType mediaType;
356 | for (int idx=0; idx < formatContext->nb_streams; ++idx) {
357 | if (idx == videoStreamIdx) {
358 | if (!(videoContext->codec->capabilities &
359 | AV_CODEC_CAP_DELAY))
360 | break;
361 | mediaType = AVMEDIA_TYPE_VIDEO;
362 | }
363 | else if (idx == audioStreamIdx) {
364 | if (!(audioContext->codec->capabilities &
365 | AV_CODEC_CAP_DELAY))
366 | break;
367 | mediaType = AVMEDIA_TYPE_AUDIO;
368 | }
369 | else {
370 | break;
371 | }
372 |
373 | av_log(NULL, AV_LOG_INFO, "Flushing stream #%u encoder\n", idx);
374 | while (encodeWriteFrame (NULL, mediaType));
375 | }
376 |
377 | av_write_trailer (formatContext);
378 | }
379 | closeContexts();
380 | }
381 |
382 | void FFmpegVideoWriter::closeContexts ()
383 | {
384 | avformat_free_context (formatContext);
385 | videoStreamIdx = -1;
386 | audioStreamIdx = -1;
387 | subtitleStreamIdx = -1;
388 | videoContext = nullptr;
389 | audioContext = nullptr;
390 | subtitleContext = nullptr;
391 | avcodec_free_context (&videoContext);
392 | avcodec_free_context (&audioContext);
393 | avcodec_free_context (&subtitleContext);
394 | formatContext = nullptr;
395 | inVideoScaler = nullptr;
396 | outVideoScaler = nullptr;
397 | audioWritePosition = 0;
398 | }
399 |
400 | void FFmpegVideoWriter::writeNextAudioBlock (juce::AudioSourceChannelInfo& info)
401 | {
402 | audioFifo.addToFifo (*info.buffer, info.numSamples);
403 | writeAudioFrame (false);
404 | }
405 |
406 | void FFmpegVideoWriter::writeNextVideoFrame (const juce::Image& image, const juce::int64 timestamp)
407 | {
408 | // use scaler and add interface for image processing / e.g. branding
409 | if (videoContext) {
410 | if (! outVideoScaler) {
411 | outVideoScaler = new FFmpegVideoScaler ();
412 | outVideoScaler->setupScaler (image.getWidth(),
413 | image.getHeight(),
414 | AV_PIX_FMT_BGR0,
415 | videoContext->width,
416 | videoContext->height,
417 | videoContext->pix_fmt);
418 | }
419 | AVFrame* frame = av_frame_alloc ();
420 | frame->width = videoContext->width;
421 | frame->height = videoContext->height;
422 | frame->format = videoContext->pix_fmt;
423 | frame->pts = timestamp;
424 | av_frame_set_color_range (frame, videoContext->color_range);
425 | int ret = av_image_alloc(frame->data, frame->linesize,
426 | videoContext->width,
427 | videoContext->height,
428 | videoContext->pix_fmt, 32);
429 | if (ret < 0) {
430 | DBG ("Could not allocate raw picture buffer");
431 | av_free (&frame);
432 | return;
433 | }
434 | outVideoScaler->convertImageToFrame (frame, image);
435 | encodeWriteFrame (frame, AVMEDIA_TYPE_VIDEO);
436 | }
437 | }
438 |
439 | bool FFmpegVideoWriter::writeAudioFrame (const bool flush)
440 | {
441 | if (formatContext && audioContext &&
442 | isPositiveAndBelow (audioStreamIdx, static_cast (formatContext->nb_streams)))
443 | {
444 |
445 | int numFrameSamples = audioContext->frame_size;
446 |
447 | if (audioFifo.getNumReady() >= numFrameSamples || flush) {
448 | const uint64_t channelLayout = AV_CH_LAYOUT_STEREO;
449 | const int numChannels = av_get_channel_layout_nb_channels (channelLayout);
450 | AVFrame* frame = av_frame_alloc ();
451 | frame->nb_samples = numFrameSamples;
452 | frame->format = AV_SAMPLE_FMT_FLTP;
453 | frame->channel_layout = channelLayout;
454 | frame->channels = numChannels;
455 | frame->pts = audioWritePosition;
456 | DBG ("Start writing audio frame, pts: " + String (audioWritePosition));
457 | int bufferSize = av_samples_get_buffer_size (nullptr, frame->channels, frame->nb_samples, AV_SAMPLE_FMT_FLTP, 0);
458 | float* samples = static_cast (av_malloc (bufferSize));
459 | avcodec_fill_audio_frame (frame,
460 | frame->channels,
461 | static_cast (frame->format),
462 | (const uint8_t*) (samples),
463 | bufferSize,
464 | 0);
465 |
466 | float** sampleData = new float*[numChannels];
467 | for (int i=0; i < frame->channels; ++i) {
468 | sampleData[i] = samples + i * frame->nb_samples;
469 | }
470 | audioFifo.readFromFifo (sampleData, numFrameSamples);
471 |
472 | encodeWriteFrame (frame, AVMEDIA_TYPE_AUDIO);
473 |
474 | delete[] sampleData;
475 | //av_freep (buffer);
476 |
477 | audioWritePosition += numFrameSamples;
478 | }
479 |
480 | return true;
481 | }
482 | return false;
483 | }
484 |
485 | int FFmpegVideoWriter::encodeWriteFrame (AVFrame *frame, AVMediaType type) {
486 | int got_frame = 0;
487 | if (formatContext) {
488 | int ret;
489 | AVPacket packet;
490 | packet.data = NULL;
491 | packet.size = 0;
492 | av_init_packet (&packet);
493 | if (type == AVMEDIA_TYPE_VIDEO) {
494 | if (frame)
495 | av_frame_set_color_range (frame, AVCOL_RANGE_JPEG);
496 | ret = avcodec_encode_video2 (videoContext, &packet, frame, &got_frame);
497 | packet.stream_index = videoStreamIdx;
498 | av_packet_rescale_ts (&packet,
499 | videoContext->time_base,
500 | formatContext->streams [videoStreamIdx]->time_base);
501 | av_frame_free (&frame);
502 | if (ret < 0) {
503 | char error[255];
504 | av_strerror (ret, error, 255);
505 | DBG (String ("Error when encoding video data: ") += error);
506 | return false;
507 | }
508 | }
509 | else if (type == AVMEDIA_TYPE_AUDIO) {
510 | ret = avcodec_encode_audio2 (audioContext, &packet, frame, &got_frame);
511 | packet.stream_index = audioStreamIdx;
512 | av_packet_rescale_ts (&packet,
513 | audioContext->time_base,
514 | formatContext->streams [audioStreamIdx]->time_base);
515 | av_frame_free (&frame);
516 | if (ret < 0) {
517 | char error[255];
518 | av_strerror (ret, error, 255);
519 | DBG (String ("Error when encoding audio data: ") += error);
520 | return false;
521 | }
522 | }
523 | else {
524 | // the AVFrame only holds audio or video data, so you shouldn't call that
525 | // function with a type other than AVMEDIA_TYPE_VIDEO or AVMEDIA_TYPE_AUDIO
526 | jassertfalse;
527 | }
528 |
529 | if (got_frame == 1) {
530 | if (av_interleaved_write_frame (formatContext, &packet) < 0) {
531 | DBG ("Error when writing data");
532 | return false;
533 | }
534 | }
535 | }
536 | else {
537 | DBG ("No writer open, did not write frame");
538 | av_frame_free (&frame);
539 | }
540 | return got_frame == 1;
541 | }
542 |
543 | void FFmpegVideoWriter::videoSizeChanged (const int width, const int height, const AVPixelFormat format)
544 | {
545 | // force a reset of scaler
546 | inVideoScaler = nullptr;
547 | }
548 |
549 | void FFmpegVideoWriter::displayNewFrame (const AVFrame* frame)
550 | {
551 | if (!inVideoScaler) {
552 | inVideoScaler = new FFmpegVideoScaler();
553 | inVideoScaler->setupScaler (frame->width, frame->height, static_cast (frame->format),
554 | videoWidth, videoHeight, AV_PIX_FMT_BGR0);
555 | }
556 | DBG ("Write video frame, pts: " + String (frame->pts));
557 | Image picture (Image::RGB, videoWidth, videoHeight, true);
558 | inVideoScaler->convertFrameToImage (picture, frame);
559 | writeNextVideoFrame (picture, frame->pts);
560 | }
561 |
562 |
563 |
--------------------------------------------------------------------------------
/modules/filmstro_ffmpeg/filmstro_ffmpeg_FFmpegVideoWriter.h:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 | Copyright (c) 2017, Filmstro Ltd. - Daniel Walz
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without modification,
7 | are permitted provided that the following conditions are met:
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 | 3. Neither the name of the copyright holder nor the names of its contributors
14 | may be used to endorse or promote products derived from this software without
15 | specific prior written permission.
16 |
17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
26 | OF THE POSSIBILITY OF SUCH DAMAGE.
27 | ==============================================================================
28 | \class FFmpegVideoWriter
29 | \file filmstro_ffmpeg_FFmpegVideoWriter.h
30 | \brief A class to write a video stream using FFmpeg
31 |
32 | \author Daniel Walz @ filmstro.com
33 | \date September 19th 2016
34 |
35 | \description Use this writer to write audio frames and video frames in a
36 | video file using ffmpeg
37 | ==============================================================================
38 | */
39 |
40 |
41 | #ifndef FILMSTRO_FFMPEG_FFMPEGVIDEOWRITER_H_INCLUDED
42 | #define FILMSTRO_FFMPEG_FFMPEGVIDEOWRITER_H_INCLUDED
43 |
44 | class FFmpegVideoSource;
45 |
46 |
47 | class FFmpegVideoWriter : public FFmpegVideoListener
48 | {
49 | public:
50 |
51 | FFmpegVideoWriter (const juce::String& format = juce::String());
52 | ~FFmpegVideoWriter();
53 |
54 | /** Set the requested video codec before opening a file */
55 | void setVideoCodec (AVCodecID codec = AV_CODEC_ID_PROBE);
56 | /** Set the requested audio codec before opening a file */
57 | void setAudioCodec (AVCodecID codec = AV_CODEC_ID_PROBE);
58 | /** Set the requested subtitle codec before opening a file */
59 | void setSubtitleCodec (AVCodecID codec = AV_CODEC_ID_PROBE);
60 |
61 | /** Set the audio sample rate before opening a file */
62 | void setSampleRate (const int newSampleRate);
63 |
64 | /** Set the video size before opening a file */
65 | void setVideoSize (const int width, const int height);
66 |
67 | /** Set the pixel format before opening a file */
68 | void setPixelFormat (const AVPixelFormat format);
69 |
70 | /** Set the pixel aspect ratio as fraction before opening a file */
71 | void setPixelAspect (const int num, const int den);
72 |
73 | /** Set the timebase for the stream, provide either
74 | AVMEDIA_TYPE_VIDEO, AVMEDIA_TYPE_AUDIO, AVMEDIA_TYPE_SUBTITLE */
75 | void setTimeBase (AVMediaType type, AVRational timebase);
76 |
77 | /** copies settings from a context (e.g. FFmpegVideoReader) to the writer */
78 | void copySettingsFromContext (const AVCodecContext* context);
79 |
80 | /** Opens a file for writing audio, video and subtitles. The settings like
81 | encoders, samplerate etc. has to be set first. */
82 | bool openMovieFile (const juce::File& outputFile, const juce::String& format=juce::String());
83 |
84 | /** Closes the movie file. Also flushes all left over samples and frames */
85 | void closeMovieFile ();
86 |
87 | /** Append a chunk of audio data. It will call writeAudioFrame to get rid of the data */
88 | void writeNextAudioBlock (juce::AudioSourceChannelInfo& info);
89 |
90 | /** Write the next video frame from juce image */
91 | void writeNextVideoFrame (const juce::Image& image, const juce::int64 timestamp);
92 |
93 | void videoSizeChanged (const int width, const int height, const AVPixelFormat) override;
94 |
95 | /** This callback receives frames from e.g. the FFmpegVideoReader to be written to the video file.
96 | The timestamp has to be set in the frame. */
97 | void displayNewFrame (const AVFrame*) override;
98 |
99 | /** Returns the names of available output formats */
100 | static juce::StringArray getOutputFormatNames ();
101 |
102 | // ==============================================================================
103 | private:
104 |
105 | void closeContexts ();
106 |
107 | void finishWriting ();
108 |
109 | /** Write audio data to frame, if there is enough. If flush is set to true, it will append silence to fill the last frame. */
110 | bool writeAudioFrame (const bool flush=false);
111 |
112 | int encodeWriteFrame (AVFrame *frame, AVMediaType type);
113 |
114 | // ==============================================================================
115 |
116 | /** This is the samplecode of the next sample to be written */
117 | juce::int64 audioWritePosition;
118 |
119 | AVFormatContext* formatContext;
120 |
121 | AVCodecContext* videoContext;
122 | AVCodecContext* audioContext;
123 | AVCodecContext* subtitleContext;
124 |
125 | AVCodecID videoCodec;
126 | AVCodecID audioCodec;
127 | AVCodecID subtitleCodec;
128 |
129 | int videoStreamIdx;
130 | int audioStreamIdx;
131 | int subtitleStreamIdx;
132 |
133 | AVRational videoTimeBase;
134 | AVRational audioTimeBase;
135 | AVRational subtitleTimeBase;
136 |
137 | int sampleRate;
138 | int64_t channelLayout;
139 |
140 | int videoWidth;
141 | int videoHeight;
142 | AVPixelFormat pixelFormat;
143 | AVRational pixelAspect;
144 |
145 | // buffer audio to match the video's audio frame size
146 | AudioBufferFIFO audioFifo;
147 |
148 | juce::ScopedPointer outVideoScaler;
149 | juce::ScopedPointer inVideoScaler;
150 |
151 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FFmpegVideoWriter)
152 | };
153 |
154 | #endif /* FILMSTRO_FFMPEG_FFMPEGVIDEOWRITER_H_INCLUDED */
155 |
156 |
--------------------------------------------------------------------------------