Release 4.0.0-preview1-00243
[platform/core/csapi/tizenfx.git] / src / Tizen.Multimedia.Recorder / Recorder / VideoRecorder.cs
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 using System;
18 using System.Diagnostics;
19 using Native = Interop.Recorder;
20 using NativeHandle = Interop.RecorderHandle;
21
22 namespace Tizen.Multimedia
23 {
24     /// <summary>
25     /// Provides the ability to control video recording.
26     /// </summary>
27     public partial class VideoRecorder : Recorder
28     {
29         private static NativeHandle CreateHandle(Camera camera)
30         {
31             if (camera == null)
32             {
33                 throw new ArgumentNullException(nameof(camera));
34             }
35
36             Native.CreateVideo(camera.Handle, out var handle).
37                 ThrowIfError("Failed to create video recorder.");
38
39             return handle;
40         }
41
42         private static void ThrowIfCodecAndFormatNotValid(RecorderVideoCodec videoCodec,
43             RecorderAudioCodec audioCodec, RecorderFileFormat fileFormat)
44         {
45             videoCodec.ThrowIfFormatNotSupported(fileFormat);
46
47             if (audioCodec != RecorderAudioCodec.None)
48             {
49                 audioCodec.ThrowIfFormatNotSupported(fileFormat);
50             }
51         }
52
53         /// <summary>
54         /// Initializes a new instance of the <see cref="VideoRecorder"/> class with the specified camera, video codec and file format.
55         /// </summary>
56         /// <remarks>
57         /// If the state of <see cref="Camera"/> is <see cref="CameraState.Created"/>,
58         /// the <see cref="CameraSettings.PreviewPixelFormat"/> will be changed to the recommended format for recording.\n
59         /// \n
60         /// The initial state of the Recorder will be <see cref="RecorderState.Ready"/>
61         /// if the state of <see cref="Camera"/> is <see cref="CameraState.Preview"/> or <see cref="CameraState.Captured"/>.
62         /// </remarks>
63         /// <param name="camera">The camera object.</param>
64         /// <param name="videoCodec">The codec for video encoding.</param>
65         /// <param name="fileFormat">The format of result file.</param>
66         /// <feature>http://tizen.org/feature/camera</feature>
67         /// <exception cref="InvalidOperationException">An internal error occurred.</exception>
68         /// <exception cref="NotSupportedException">
69         ///     A required feature is not supported.\n
70         ///     -or-\n
71         ///     <paramref name="videoCodec"/> is not supported.\n
72         ///     -or-\n
73         ///     <paramref name="fileFormat"/> is not supported with the specified video codec.
74         /// </exception>
75         /// <exception cref="ArgumentException">
76         ///     <paramref name="videoCodec"/> is not valid.\n
77         ///     -or-\n
78         ///     <paramref name="fileFormat"/> is not valid.\n
79         ///     -or-\n
80         ///     <paramref name="camera"/> is being used by another object.
81         /// </exception>
82         /// <exception cref="ObjectDisposedException"><paramref name="camera"/> has been disposed of.</exception>
83         /// <exception cref="ArgumentNullException"><paramref name="camera"/> is null.</exception>
84         /// <seealso cref="GetSupportedVideoCodecs"/>
85         /// <seealso cref="Recorder.GetSupportedFileFormats"/>
86         /// <seealso cref="RecorderExtensions.GetSupportedFileFormats(RecorderVideoCodec)"/>
87         /// <seealso cref="SetFormatAndCodec(RecorderVideoCodec, RecorderFileFormat)"/>
88         /// <seealso cref="SetFormatAndCodec(RecorderVideoCodec, RecorderAudioCodec, RecorderFileFormat)"/>
89         public VideoRecorder(Camera camera, RecorderVideoCodec videoCodec, RecorderFileFormat fileFormat) :
90             this(camera, videoCodec, RecorderAudioCodec.None, fileFormat)
91         {
92         }
93
94         /// <summary>
95         /// Initializes a new instance of the <see cref="VideoRecorder"/> class with the specified camera, video codec,
96         /// audio codec and file format.
97         /// </summary>
98         /// <remarks>
99         /// If the state of <see cref="Camera"/> is <see cref="CameraState.Created"/>,
100         /// the <see cref="CameraSettings.PreviewPixelFormat"/> will be changed to the recommended format for recording.\n
101         /// \n
102         /// The initial state of the Recorder will be <see cref="RecorderState.Ready"/>
103         /// if the state of <see cref="Camera"/> is <see cref="CameraState.Preview"/> or <see cref="CameraState.Captured"/>.
104         /// </remarks>
105         /// <param name="camera">The camera object.</param>
106         /// <param name="videoCodec">The codec for video encoding.</param>
107         /// <param name="audioCodec">The codec for audio encoding.</param>
108         /// <param name="fileFormat">The format of result file.</param>
109         /// <feature>http://tizen.org/feature/camera</feature>
110         /// <exception cref="InvalidOperationException">An internal error occurred.</exception>
111         /// <exception cref="NotSupportedException">
112         ///     A required feature is not supported.\n
113         ///     -or-\n
114         ///     <paramref name="videoCodec"/> is not supported.\n
115         ///     -or-\n
116         ///     <paramref name="audioCodec"/> is not supported.\n
117         ///     -or-\n
118         ///     <paramref name="fileFormat"/> is not supported with the specified video codec.
119         ///     -or-\n
120         ///     <paramref name="fileFormat"/> is not supported with the specified audio codec.
121         /// </exception>
122         /// <exception cref="ArgumentException">
123         ///     <paramref name="videoCodec"/> is not valid.\n
124         ///     -or-\n
125         ///     <paramref name="audioCodec"/> is not valid.\n
126         ///     -or-\n
127         ///     <paramref name="fileFormat"/> is not valid.
128         /// </exception>
129         /// <exception cref="ObjectDisposedException"><paramref name="camera"/> has been disposed of.</exception>
130         /// <exception cref="ArgumentNullException"><paramref name="camera"/> is null.</exception>
131         /// <seealso cref="Recorder.GetSupportedAudioCodecs"/>
132         /// <seealso cref="GetSupportedVideoCodecs"/>
133         /// <seealso cref="Recorder.GetSupportedFileFormats"/>
134         /// <seealso cref="RecorderExtensions.GetSupportedFileFormats(RecorderAudioCodec)"/>
135         /// <seealso cref="RecorderExtensions.GetSupportedFileFormats(RecorderVideoCodec)"/>
136         /// <seealso cref="SetFormatAndCodec(RecorderVideoCodec, RecorderFileFormat)"/>
137         /// <seealso cref="SetFormatAndCodec(RecorderVideoCodec, RecorderAudioCodec, RecorderFileFormat)"/>
138         public VideoRecorder(Camera camera, RecorderVideoCodec videoCodec,
139             RecorderAudioCodec audioCodec, RecorderFileFormat fileFormat) : base(CreateHandle(camera))
140         {
141             SetFormatAndCodec(videoCodec, RecorderAudioCodec.None, fileFormat);
142         }
143
144         /// <summary>
145         /// Sets the video codec and the file format for recording. Audio will not recorded.
146         /// </summary>
147         /// <param name="videoCodec">The codec for video encoding.</param>
148         /// <param name="fileFormat">The format of result file.</param>
149         /// <exception cref="NotSupportedException">
150         ///     <paramref name="videoCodec"/> is not supported.\n
151         ///     -or-\n
152         ///     <paramref name="fileFormat"/> is not supported with the specified video codec.
153         /// </exception>
154         /// <exception cref="ArgumentException">
155         ///     <paramref name="videoCodec"/> is not valid.\n
156         ///     -or-\n
157         ///     <paramref name="fileFormat"/> is not valid.
158         /// </exception>
159         /// <seealso cref="GetSupportedVideoCodecs"/>
160         /// <seealso cref="Recorder.GetSupportedFileFormats"/>
161         /// <seealso cref="RecorderExtensions.GetSupportedFileFormats(RecorderVideoCodec)"/>
162         /// <seealso cref="SetFormatAndCodec(RecorderVideoCodec, RecorderAudioCodec, RecorderFileFormat)"/>
163         /// <seealso cref="Recorder.Start(string)"/>
164         public void SetFormatAndCodec(RecorderVideoCodec videoCodec, RecorderFileFormat fileFormat)
165         {
166             SetFormatAndCodec(videoCodec, RecorderAudioCodec.None, fileFormat);
167         }
168
169         /// <summary>
170         /// Sets the video codec, audio codec and the file format for recording.
171         /// </summary>
172         /// <param name="videoCodec">The codec for video encoding.</param>
173         /// <param name="audioCodec">The codec for audio encoding.</param>
174         /// <param name="fileFormat">The format of result file.</param>
175         /// <exception cref="NotSupportedException">
176         ///     <paramref name="videoCodec"/> is not supported.\n
177         ///     -or-\n
178         ///     <paramref name="audioCodec"/> is not supported.\n
179         ///     -or-\n
180         ///     <paramref name="fileFormat"/> is not supported with the specified video codec.
181         ///     -or-\n
182         ///     <paramref name="fileFormat"/> is not supported with the specified audio codec.
183         /// </exception>
184         /// <exception cref="ArgumentException">
185         ///     <paramref name="videoCodec"/> is not valid.\n
186         ///     -or-\n
187         ///     <paramref name="audioCodec"/> is not valid.\n
188         ///     -or-\n
189         ///     <paramref name="fileFormat"/> is not valid.
190         /// </exception>
191         /// <seealso cref="Recorder.GetSupportedAudioCodecs"/>
192         /// <seealso cref="VideoRecorder.GetSupportedVideoCodecs"/>
193         /// <seealso cref="Recorder.GetSupportedFileFormats"/>
194         /// <seealso cref="RecorderExtensions.GetSupportedFileFormats(RecorderAudioCodec)"/>
195         /// <seealso cref="RecorderExtensions.GetSupportedFileFormats(RecorderVideoCodec)"/>
196         /// <seealso cref="SetFormatAndCodec(RecorderVideoCodec, RecorderFileFormat)"/>
197         /// <seealso cref="Recorder.Start(string)"/>
198         public void SetFormatAndCodec(RecorderVideoCodec videoCodec, RecorderAudioCodec audioCodec, RecorderFileFormat fileFormat)
199         {
200             ThrowIfCodecAndFormatNotValid(videoCodec, audioCodec, fileFormat);
201
202             VideoCodec = videoCodec;
203             AudioCodec = audioCodec;
204             FileFormat = fileFormat;
205         }
206
207         #region Properties
208
209         private RecorderVideoCodec _videoCodec;
210
211         /// <summary>
212         /// Gets the audio codec for encoding an audio stream.
213         /// </summary>
214         public RecorderVideoCodec VideoCodec
215         {
216             get => _videoCodec;
217             internal set
218             {
219                 Debug.Assert(Enum.IsDefined(typeof(RecorderVideoCodec), value));
220
221                 ValidateVideoCodec(value);
222
223                 Native.SetVideoEncoder(Handle, value).ThrowIfError("Failed to set video codec.");
224
225                 _videoCodec = value;
226             }
227         }
228
229         /// <summary>
230         /// Gets or sets the video recording motion rate.
231         /// </summary>
232         /// <remarks>
233         /// The attribute is valid only in a video recorder.\n
234         /// If the rate is in range of 0-1, the video is recorded in a slow motion mode.\n
235         /// If the rate is bigger than 1, the video is recorded in a fast motion mode.\n
236         /// \n
237         /// To set, the recorder must be in the <see cref="RecorderState.Idle"/> or the <see cref="RecorderState.Ready"/> state.
238         /// </remarks>
239         /// <exception cref="ArgumentOutOfRangeException">The <paramref name="value"/> is less than or equal to 0.</exception>
240         /// <exception cref="InvalidOperationException">The recorder is not in the valid state.</exception>
241         /// <exception cref="ObjectDisposedException">The recorder already has been disposed of.</exception>
242         public double VideoMotionRate
243         {
244             get
245             {
246                 Native.GetMotionRate(Handle, out var val).ThrowIfError("Failed to get video motion rate.");
247
248                 return val;
249             }
250
251             set
252             {
253                 ValidateState(RecorderState.Idle, RecorderState.Ready);
254
255                 if (value <= 0)
256                 {
257                     throw new ArgumentOutOfRangeException(nameof(value), value,
258                         "Video Motion rate can't be less than zero.");
259                 }
260
261                 Native.SetMotionRate(Handle, value).
262                     ThrowIfError("Failed to set video motion rate");
263             }
264         }
265
266         /// <summary>
267         /// Gets or sets the orientation in the video metadata tag.
268         /// </summary>
269         /// <value>A <see cref="Rotation"/> that specifies the type of orientation.</value>
270         /// <exception cref="ArgumentException"><paramref name="value"/> is not valid.</exception>
271         /// <exception cref="ObjectDisposedException">The recorder already has been disposed of.</exception>
272         public Rotation VideoOrientationTag
273         {
274             get
275             {
276                 Native.GetOrientationTag(Handle, out var val).ThrowIfError("Failed to get recorder orientation.");
277
278                 return val;
279             }
280
281             set
282             {
283                 ValidationUtil.ValidateEnum(typeof(Rotation), value, nameof(value));
284
285                 Native.SetOrientationTag(Handle, value).
286                     ThrowIfError("Failed to set recorder orientation");
287             }
288         }
289
290         /// <summary>
291         /// Gets or sets the resolution of the video recording.
292         /// </summary>
293         /// <remarks>
294         /// To set, the recorder must be in the <see cref="RecorderState.Idle"/> or the <see cref="RecorderState.Ready"/> state.
295         /// </remarks>
296         /// <exception cref="ArgumentOutOfRangeException">Width or height of <paramref name="value"/> is less than or equal to zero.</exception>
297         /// <exception cref="NotSupportedException"><paramref name="value"> is not supported.</exception>
298         /// <exception cref="InvalidOperationException">The recorder is not in the valid state.</exception>
299         /// <exception cref="ObjectDisposedException">The recorder already has been disposed of.</exception>
300         /// <seealso cref="Recorder.GetSupportedVideoResolutions(CameraDevice)"/>
301         public Size VideoResolution
302         {
303             get
304             {
305                 Native.GetVideoResolution(Handle, out var width, out var height).
306                     ThrowIfError("Failed to get camera video resolution");
307
308                 return new Size(width, height);
309             }
310
311             set
312             {
313                 ValidateState(RecorderState.Idle, RecorderState.Ready);
314
315                 if (value.Width <= 0 || value.Height <= 0)
316                 {
317                     throw new ArgumentOutOfRangeException(nameof(value), value,
318                         "Resolution can't be less than or equal to zero.");
319                 }
320
321                 var ret = Native.SetVideoResolution(Handle, value.Width, value.Height);
322
323                 if (ret == RecorderErrorCode.InvalidParameter)
324                 {
325                     throw new NotSupportedException($"Resolution({value.ToString()}) is not supported.");
326                 }
327
328                 ret.ThrowIfError("Failed to set video resolution.");
329             }
330         }
331
332         /// <summary>
333         /// Gets or sets the bitrate of the video encoder in bits per second.
334         /// </summary>
335         /// <remarks>
336         /// To set, the recorder must be in the <see cref="RecorderState.Idle"/> or <see cref="RecorderState.Ready"/> state.
337         /// </remarks>
338         /// <exception cref="ArgumentOutOfRangeException"><paramref name="value"/> is less than or equal to zero.</exception>
339         /// <exception cref="InvalidOperationException">The recorder is not in the valid state.</exception>
340         /// <exception cref="ObjectDisposedException">The recorder already has been disposed of.</exception>
341         public int VideoBitRate
342         {
343             get
344             {
345                 Native.GetVideoEncoderBitrate(Handle, out var val).ThrowIfError("Failed to get video bitrate.");
346
347                 return val;
348             }
349
350             set
351             {
352                 ValidateState(RecorderState.Idle, RecorderState.Ready);
353
354                 if (value <= 0)
355                 {
356                     throw new ArgumentOutOfRangeException(nameof(value), value,
357                         "Bit rate can't be less than or equal to zero.");
358                 }
359
360                 Native.SetVideoEncoderBitrate(Handle, value).
361                     ThrowIfError("Failed to set video bitrate");
362             }
363         }
364
365         #endregion
366     }
367 }