<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Hyeonju’s Atelier</title>
        <link>https://velog.io/</link>
        <description>소통과 발전을 중요시 하는 소프트웨어엔지니어</description>
        <lastBuildDate>Sat, 24 Jan 2026 05:39:28 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Hyeonju’s Atelier</title>
            <url>https://velog.velcdn.com/images/hyeonju_jo/profile/bf249aa9-5b65-4be9-a47b-702a81246a4a/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. Hyeonju’s Atelier. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/hyeonju_jo" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Python] Hash Map과 List를 활용한 O(N) 효율적 위치 추적 구현 ([달리기 경주])]]></title>
            <link>https://velog.io/@hyeonju_jo/Python-Hash-Map%EA%B3%BC-List%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-ON-%ED%9A%A8%EC%9C%A8%EC%A0%81-%EC%9C%84%EC%B9%98-%EC%B6%94%EC%A0%81-%EA%B5%AC%ED%98%84-%EB%8B%AC%EB%A6%AC%EA%B8%B0-%EA%B2%BD%EC%A3%BC</link>
            <guid>https://velog.io/@hyeonju_jo/Python-Hash-Map%EA%B3%BC-List%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-ON-%ED%9A%A8%EC%9C%A8%EC%A0%81-%EC%9C%84%EC%B9%98-%EC%B6%94%EC%A0%81-%EA%B5%AC%ED%98%84-%EB%8B%AC%EB%A6%AC%EA%B8%B0-%EA%B2%BD%EC%A3%BC</guid>
            <pubDate>Sat, 24 Jan 2026 05:39:28 GMT</pubDate>
            <description><![CDATA[<h3 id="🚀-introduction-왜-우리는-더-빠른-검색에-집착하는가">🚀 Introduction: 왜 우리는 더 빠른 검색에 집착하는가?</h3>
<p>오늘 다룬 문제는 단순한 &#39;순서 바꾸기&#39;처럼 보이지만, 그 이면에는 <strong>데이터 검색 속도와 성능 최적화</strong>라는 알고리즘의 핵심 과제가 숨어 있습니다. 대규모 서비스 환경에서 특정 사용자의 상태를 업데이트할 때마다 전체 명단을 처음부터 끝까지 뒤져야 한다면 어떻게 될까요? 데이터가 100만 개라면, 단 한 번의 업데이트를 위해 100만 번의 연산이 필요해집니다.</p>
<p>오늘은 리스트의 물리적 순서를 유지하면서도, 검색 성능을 <strong>$O(1)$</strong>로 끌어올리는 <strong>해시 테이블(Hash Table)</strong> 기반의 딕셔너리 활용법을 정리해 보았습니다.</p>
<hr>
<h3 id="🔍-the-challenge-deep-dive-리스트-순회-무엇이-병목bottleneck인가">🔍 The Challenge (Deep Dive): 리스트 순회, 무엇이 병목(Bottleneck)인가?</h3>
<p>처음 문제를 접했을 때 가장 직관적인 접근은 <code>for</code>문을 돌려 타겟을 찾는 방식이었습니다. 하지만 여기서 두 가지 기술적 병목을 마주했습니다.</p>
<ol>
<li><strong>데이터 유실의 위험</strong>: 단순 대입(<code>=</code>)은 추월을 구현하는 것이 아니라 기존 데이터를 &#39;덮어쓰기&#39; 때문에 선수의 정보가 유실됩니다. 즉, 데이터의 정합성을 지키기 위한 <strong>Swap(교환)</strong> 로직이 필수적이었습니다.</li>
<li><strong>선형 탐색(Linear Search)의 한계</strong>: <code>answer[i] == c</code>를 찾기 위해 매번 리스트 전체를 순회하는 이중 반복문 구조는 시간 복잡도 <strong>$O(N \times M)$</strong>을 유발합니다. $N$(선수 수)이 5만, $M$(호출 수)이 10만일 경우 연산 횟수는 최대 50억 번에 달하며, 이는 반드시 <strong>시간 초과(Time Limit Exceeded)</strong>로 이어집니다.</li>
</ol>
<hr>
<h3 id="💡-technical-insight-자료구조의-트레이드-오프trade-off">💡 Technical Insight: 자료구조의 트레이드 오프(Trade-off)</h3>
<p>이 병목을 해결하기 위해 파이썬의 <code>dict</code> 자료구조를 도입했습니다. 파이썬의 딕셔너리는 내부적으로 <strong>해시 테이블</strong>로 구현되어 있어, Key를 통해 Value를 찾는 과정이 평균적으로 <strong>$O(1)$</strong>에 수행됩니다.</p>
<p>내가 지금 손에 든 정보(선수 이름)로 무엇(인덱스)을 찾고 싶은지를 고민하여 <strong>{Name: Index}</strong> 형태의 &#39;역색인&#39; 구조를 설계했습니다.</p>
<h3 id="📊-자료구조-비교-list-vs-dict-hash-map">📊 자료구조 비교: List vs Dict (Hash Map)</h3>
<table>
<thead>
<tr>
<th><strong>자료구조</strong></th>
<th><strong>탐색 방식</strong></th>
<th><strong>시간 복잡도</strong></th>
<th><strong>비고</strong></th>
</tr>
</thead>
<tbody><tr>
<td><strong>List</strong></td>
<td>순차 탐색 (Linear)</td>
<td>$O(N)$</td>
<td>데이터가 많아질수록 탐색 시간이 정비례하여 증가함</td>
</tr>
<tr>
<td><strong>Dict (Hash)</strong></td>
<td>해시 탐색 (Hash)</td>
<td>$O(1)$</td>
<td>해시 테이블을 사용하여 데이터 양과 관계없이 <strong>즉시</strong> 찾음</td>
</tr>
</tbody></table>
<p>단, 딕셔너리만으로는 최종 정답인 &#39;선수들의 순서&#39;를 즉각 반환하기 어렵기 때문에, <strong>순서를 담당하는 리스트</strong>와 <strong>검색을 담당하는 딕셔너리</strong>를 동시에 업데이트하는 &#39;이중 장부&#39; 전략을 선택했습니다.</p>
<hr>
<h3 id="✅-the-solution--code">✅ The Solution &amp; Code</h3>
<p>최종 구현 코드</p>
<pre><code class="language-python">def solution(players, callings):
    # 1. &#39;이름: 등수&#39; 형태의 해시 맵(rank_dict) 초기화 (O(N))
    # 이름표(Key)를 주면 등수(Value)를 광속으로 찾아주는 &#39;거꾸로 사전&#39;
    rank_dict = {player: i for i, player in enumerate(players)}

    for c in callings:
        # 2. 호명된 선수의 현재 인덱스를 해시 맵에서 O(1)로 조회
        i = rank_dict[c]

        # 3. Swap을 위해 앞 순서 선수(Target) 식별
        # 자리를 바꾼 뒤에도 장부를 수정해야 하므로 이름을 미리 메모해둠(front_player)
        front_player = players[i - 1]

        # 4. List 데이터 업데이트: 실제 물리적 위치 교체 (O(1))
        # 파이썬의 튜플 언패킹을 활용한 우아한 Swap
        players[i - 1], players[i] = players[i], players[i - 1]

        # 5. Dict 데이터 업데이트: 해시 맵 내 인덱스 정보 동기화
        # 내 인덱스는 줄이고, 밀려난 앞 선수의 인덱스는 늘려줌
        rank_dict[c] -= 1
        rank_dict[front_player] += 1

    return players</code></pre>
<hr>
<h3 id="📈-summary">📈 Summary</h3>
<ul>
<li><strong>시간 복잡도</strong>: 딕셔너리 초기화($O(N)$) + 호출 순회($O(M)$) = <strong>$O(N + M)$</strong>. 최악의 상황에서도 약 15만 번의 연산으로 해결 가능합니다.</li>
<li><strong>공간 복잡도</strong>: 리스트 외에 별도의 딕셔너리를 사용하므로 <strong>$O(N)$</strong>의 추가 공간이 필요하지만, 성능 최적화를 위한 합리적인 비용(Trade-off)입니다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Google Analytics RestAPI 이벤트 전달하는법]]></title>
            <link>https://velog.io/@hyeonju_jo/Google-Analytics-RestAPI-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EC%A0%84%EB%8B%AC%ED%95%98%EB%8A%94%EB%B2%95</link>
            <guid>https://velog.io/@hyeonju_jo/Google-Analytics-RestAPI-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EC%A0%84%EB%8B%AC%ED%95%98%EB%8A%94%EB%B2%95</guid>
            <pubDate>Mon, 01 Apr 2024 02:16:37 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>본 내용은 웹 기준으로 작성되었습니다.
앱의 경우 gtag.js가 아닌 firebase로 해주세요.</p>
</blockquote>
<h1 id="google-analytics-접속">Google Analytics 접속</h1>
<ol>
<li><p><a href="https://analytics.google.com/analytics/web/#/provision">Google Analytics</a> 페이지에 접속해 줍니다.</p>
</li>
<li><p>시작
 a. 처음 시작이라면 측정 시작을 눌러주세요.
 b. 이미 만들어 두었다면 오른쪽 상단 네모 버튼을 눌러 <strong>애널리틱스</strong>를 클릭해 주세요.
<img src="https://velog.velcdn.com/images/hyeonju_jo/post/10d1b6d1-a5a1-46be-b3d0-a542a09b4bd5/image.png" alt=""></p>
</li>
</ol>
<h1 id="필요한-매개변수-찾기">필요한 매개변수 찾기</h1>
<p><a href="https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference?hl=ko&amp;client_type=firebase">측정 프로토콜 참조  |  Google 애널리틱스  |  Google for Developers</a></p>
<hr>
<ol>
<li>생성한 애널리틱스로 들어가 왼쪽 메뉴바에서 <strong>관리</strong>로 들어가줍니다.
<img src="https://velog.velcdn.com/images/hyeonju_jo/post/72ef93f9-05fa-478e-8997-433bc9dfddad/image.png" alt=""></li>
</ol>
<ol start="2">
<li>속성 설정 → 데이터 수집 및 수정 → <strong>데이터 스트림</strong> 선택
<img src="https://velog.velcdn.com/images/hyeonju_jo/post/b85a4efd-883d-40e6-a284-b9e6eca7c65c/image.png" alt=""></li>
</ol>
<ol start="3">
<li>해당하는 플랫폼을 선택해 주세요.
<img src="https://velog.velcdn.com/images/hyeonju_jo/post/f6689860-a0cf-4f67-8215-7508bd335229/image.png" alt=""></li>
</ol>
<ol start="4">
<li>웹사이트 URL과 스트림 이름을 작성한 뒤 하단에 <strong>스트림 만들기</strong> 클릭
<img src="https://velog.velcdn.com/images/hyeonju_jo/post/75964ee9-6e53-4b8f-9159-f02424971891/image.png" alt=""></li>
</ol>
<ol start="5">
<li><strong>측정 ID</strong> 복사 후 메모장에 붙여넣어 주세요.
a. 측정 ID가 measurement_id가 됩니다.
<img src="https://velog.velcdn.com/images/hyeonju_jo/post/b5ddf4c3-8a95-457b-978c-4f86beac1307/image.png" alt=""></li>
</ol>
<ol start="6">
<li>스크롤을 내린 후 <strong>측정 프로토콜 API 비밀번호</strong>를 클릭해주세요.
<img src="https://velog.velcdn.com/images/hyeonju_jo/post/feffca7f-09f1-413a-8e46-4a45c20f476c/image.png" alt=""></li>
</ol>
<ol start="7">
<li><strong>비밀번호 값</strong> 을 복사 후 메모장에 붙여넣어주세요.
a. 비밀번호 값이 ap_secret이 됩니다.
<img src="https://velog.velcdn.com/images/hyeonju_jo/post/e51aff44-91b5-480b-acaa-8ad648f8a8ca/image.png" alt=""></li>
</ol>
<h1 id="postman으로-테스트-하기">Postman으로 테스트 하기</h1>
<ol>
<li>Postman method를 <strong>Post</strong>로 지정해줍니다.
<img src="https://velog.velcdn.com/images/hyeonju_jo/post/c6bc20cf-0a1d-4b67-82f6-79c628e87980/image.png" alt=""></li>
</ol>
<ol start="2">
<li>URL에 <a href="https://www.google-analytics.com/mp/collect">https://www.google-analytics.com/mp/collect</a> 을 넣어줍니다.
<img src="https://velog.velcdn.com/images/hyeonju_jo/post/a04deff9-ddd7-4c53-92da-76df80984280/image.png" alt=""></li>
</ol>
<ol start="3">
<li>body → raw → JSON 선택 아래와 같이 원하는 키와 값을 넣어줍니다.
a. <a href="https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference?hl=ko&amp;client_type=firebase">측정 프로토콜 참조  |  Google 애널리틱스  |  Google for Developers</a> 참조
<img src="https://velog.velcdn.com/images/hyeonju_jo/post/ff1b5494-de81-46ce-8e40-ac3d9cc169e7/image.png" alt=""></li>
</ol>
<ol start="4">
<li>보고서 → <strong>실시간</strong>으로 들어가 주세요.
a. 실시간이 아니면 내역이 바로뜨지 않습니다.
b. 실시간 또한 약 10~30초 정도 딜레이가 있습니다.
<img src="https://velog.velcdn.com/images/hyeonju_jo/post/8beb2d18-3943-4238-b59f-6ff5a414f145/image.png" alt=""></li>
</ol>
<ol start="5">
<li>실시간에서 여러 요소 중 이벤트를 확인할 수 있습니다.
<img src="https://velog.velcdn.com/images/hyeonju_jo/post/d5b7664a-46b6-4e67-9802-10914894dda6/image.png" alt=""></li>
</ol>
<h1 id="연동-안될-경우-해결법">연동 안될 경우 해결법</h1>
<h2 id="postman에서-204가-떴는데-실시간에-아무런-변화가-없을-경우">Postman에서 204가 떴는데 실시간에 아무런 변화가 없을 경우</h2>
<ul>
<li>Postman에서 204가 뜨는건 정상이지만 아무런 변화가 없을 경우 Params의 값들을 다시 확인해 주세요.</li>
<li>Postman의 URL 주소를 <a href="https://www.google-analytics.com/debug/mp/collect">https://www.google-analytics.com/debug/mp/collect</a> 로 바꿔주세요.
에러 내용을 확인할 수 있습니다.</li>
</ul>
<h2 id="params의-값에-아무런-문제가-없고-204만-뜰-경우">Params의 값에 아무런 문제가 없고, 204만 뜰 경우</h2>
<ol>
<li><p>Event Builder에 접속해 주세요.
<a href="https://ga-dev-tools.google/ga4/event-builder/">ga-dev-tools.google</a></p>
</li>
<li><p>client를 gtag.js로 해주세요.
<img src="https://velog.velcdn.com/images/hyeonju_jo/post/fc7f860f-3256-4a29-9404-7656f053e2b2/image.png" alt=""></p>
</li>
</ol>
<ol start="3">
<li>위쪽 빨간칸에 해당하는 내용을 작성해 주세요.<ol>
<li>아래 칸은 자동으로 맞춰 채워집니다.</li>
<li>client_id는 임의의 값을 입력해도 괜찮습니다.</li>
<li>*표시가 없다면 입력하지 않아도괜찮습니다.
<img src="https://velog.velcdn.com/images/hyeonju_jo/post/fd632a53-bf71-40cd-a85f-6fcf7c89669a/image.png" alt=""></li>
</ol>
</li>
</ol>
<ol start="4">
<li>event_name을 정해주세요.
<img src="https://velog.velcdn.com/images/hyeonju_jo/post/0ead11de-afdc-483a-89dc-b3a42847bbf7/image.png" alt=""></li>
</ol>
<ol start="5">
<li>스크롤을 아래로 내려 <strong>VALIDATE EVENT</strong> 버튼을 클릭해 주세요.
<img src="https://velog.velcdn.com/images/hyeonju_jo/post/0f0dbf3f-20cf-4eae-9748-a3823b7d8028/image.png" alt=""></li>
</ol>
<ol start="6">
<li>유효하지 않다면 다음과 같이 메세지를 줍니다.
<img src="https://velog.velcdn.com/images/hyeonju_jo/post/927f4ab8-db25-4a29-ae03-2b7ab880acd5/image.png" alt=""></li>
</ol>
<ol start="7">
<li><p>값이 유효하다면 다음과 같이 뜨고,** SEND TO GA**를 클릭하면 Postman과 같이 값이 전달 됩니다.
<img src="https://velog.velcdn.com/images/hyeonju_jo/post/4452d057-6363-4113-b8d6-0b1c472e7a37/image.png" alt=""></p>
</li>
<li><p>COPY PAYLOAD를 클릭하면 Body를 JSON 형태로 보여주며, Postman에 붙여 넣을 수 있습니다.</p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[FFmpeg] 소개 및 설치]]></title>
            <link>https://velog.io/@hyeonju_jo/FFmpeg-%EC%86%8C%EA%B0%9C-%EB%B0%8F-%EC%84%A4%EC%B9%98</link>
            <guid>https://velog.io/@hyeonju_jo/FFmpeg-%EC%86%8C%EA%B0%9C-%EB%B0%8F-%EC%84%A4%EC%B9%98</guid>
            <pubDate>Tue, 16 Jan 2024 03:52:27 GMT</pubDate>
            <description><![CDATA[<h1 id="ffmpeg-소개">FFmpeg 소개</h1>
<blockquote>
<p><strong>FFmpeg</strong>은 멀티미디어 분야에서 가장 많이 사용되는 오픈소스
광범위한 멀티미디어 데이터를 다루는 데 사용되는 강력한 오픈 소스 소프트웨어
비디오, 오디오, 이미지 파일 등 다양한 형식의 멀티미디어 파일을 처리, 변환, 스트리밍하는 데 사용
<strong>Michael Niedermayer</strong>의 주도하여 개발되고 있다.</p>
</blockquote>
<h2 id="디코더">디코더</h2>
<ul>
<li>동영상을 재생할때 쓰이는 코덱</li>
</ul>
<h3 id="ffmpeg-기반-동영상-플레이어">FFmpeg 기반 동영상 플레이어</h3>
<ul>
<li><strong>iOS:</strong> AV player, nPlayer</li>
<li><strong>안드로이드:</strong> Dice Player, MX 플레이어, 안드로이드용 곰플레이어, 안드로이드용 KMPlayer</li>
<li><strong>Microsoft Windows:</strong> 팟플레이어, 곰플레이어, KMPlayer, MPC-HC, 콘플레이어</li>
<li><strong>macOS:</strong> 무비스트, IINA</li>
<li><strong>크로스 플랫폼:</strong> VLC, MPlayer</li>
</ul>
<p>외에 더 많은 플레이어들이 있다.</p>
<h3 id="ffmpeg-기반-코덱">FFmpeg 기반 코덱</h3>
<ul>
<li>LAVFilters</li>
<li>FFDshow</li>
</ul>
<p>외에 LAVFilters, FFDshow를 기반으로 한 코덱들</p>
<h2 id="인코더">인코더</h2>
<p>동영상 편집 프로그램에서 최종 결과물을 내보낼때 거치는 도구</p>
<h3 id="ffmpeg-기반-인코더">FFmpeg 기반 인코더</h3>
<ul>
<li>제트오디오VX(무료 혹은 유료, 코원)</li>
<li>유마일</li>
<li>엔젤인코더</li>
<li>샤나인코더</li>
<li>Freemake - 서양에서 유명한 인코딩 프로그램. 그러나 랜섬웨어 유포 위험이 있다.</li>
<li>Mencoder</li>
<li>곰인코더</li>
<li>다음팟인코더</li>
<li>Handbrake - 세계에서 가장 많이 쓰이는 인코더</li>
<li>WInff - FFmpeg를 GUI로 만든 프로그램</li>
</ul>
<h2 id="ffmpeg-기능">FFmpeg 기능</h2>
<ul>
<li><p><strong>변환(Transcoding):</strong> FFmpeg는 한 형식의 비디오나 오디오 파일을 다른 형식으로 변환할 수 있다. 예를 들어, AVI 파일을 MP4로 변환하거나 WAV 오디오 파일을 MP3로 변환하는 것이 가능</p>
</li>
<li><p><strong>스트리밍(Streaming):</strong> FFmpeg를 사용하여 라이브 비디오와 오디오 스트림을 인코딩하고, 인터넷을 통해 방송할 수 있다.</p>
</li>
<li><p><strong>비디오 편집(Video Editing):</strong> FFmpeg는 기본적인 비디오 편집 기능을 제공 예를 들어, 비디오를 자르거나, 여러 클립을 합치거나, 비디오에서 오디오를 분리하는 것이 가능</p>
</li>
<li><p><strong>오디오 편집(Audio Editing):</strong> 오디오 파일의 볼륨 조절, 샘플레이트 변경, 채널 조정 등 기본적인 오디오 편집 기능</p>
</li>
<li><p><strong>비디오 필터(Video Filters):</strong> 다양한 비디오 필터를 사용하여 비디오의 모습을 변경할 수 있습니다. 예를 들어, 컬러 조정, 이미지 오버레이, 텍스트 추가 등이 있다.</p>
</li>
<li><p><strong>오디오 필터(Audio Filters):</strong> 오디오에 대한 다양한 필터링 기능을 제공하여 소리를 변경하거나 개선할 수 있다.</p>
</li>
<li><p><strong>프레임 추출(Frame Extraction):</strong> 비디오에서 특정 프레임을 이미지 파일로 추출하는 기능 제공</p>
</li>
<li><p><strong>메타데이터 관리(Metadata Handling):</strong> 멀티미디어 파일의 메타데이터를 조회하거나 수정할 수 있다.</p>
</li>
<li><p><strong>코덱 정보 조회(Codec Information):</strong> 다양한 코덱과 포맷에 대한 정보를 조회할 수 있으며, FFmpeg는 많은 코덱을 지원</p>
</li>
<li><p><strong>배치 처리(Batch Processing):</strong> 스크립트를 사용하여 대량의 파일을 자동으로 처리할 수 있다.</p>
</li>
</ul>
<h1 id="ffmpeg-설치">FFmpeg 설치</h1>
<ol>
<li><p>홈페이지 들어가기
<a href="https://ffmpeg.org/">FFmpeg 공식 홈페이지</a></p>
</li>
<li><p>다운로드 클릭
<img src="https://velog.velcdn.com/images/hyeonju_jo/post/843cefd8-ceb9-42cf-8cfc-30163bb43479/image.png" alt="다운로드"></p>
</li>
<li><p>윈도우 -&gt; Windows builds from gyan.dev 클릭
<img src="https://velog.velcdn.com/images/hyeonju_jo/post/a42be393-f600-4f8b-b6c5-7e45b761d381/image.png" alt=""></p>
</li>
<li><p>ffmpeg-git 파일 중 원하는 것 클릭
essentials은 많이 사용되는 패키지만 포함되어 있다.</p>
</li>
</ol>
<ul>
<li>다운로드
<img src="https://velog.velcdn.com/images/hyeonju_jo/post/443ffcf2-eac8-4f7f-bf73-e2e1a91fdc29/image.png" alt=""></li>
</ul>
<ol start="5">
<li>개발용은 Release 파일 사용
<img src="https://velog.velcdn.com/images/hyeonju_jo/post/289fc8b8-2d6a-42fb-94c0-8a6816d94015/image.png" alt=""></li>
</ol>
<ol start="6">
<li>원하는 경로에 압축을 해제해 줍니다.</li>
</ol>
<h1 id="실행-방법">실행 방법</h1>
<p>두 가지의 경우가 있는데 편한 방법으로 사용하면 된다.</p>
<ol>
<li>해당 파일 경로로 실행</li>
<li>환경 변수 설정</li>
</ol>
<h2 id="경로로-실행">경로로 실행</h2>
<ol>
<li><p>ffmpeg bin 폴더로 이동
<img src="https://velog.velcdn.com/images/hyeonju_jo/post/0d6fc4b7-3718-464c-9938-060aa9023eb2/image.png" alt=""></p>
</li>
<li><p>경로 클릭
<img src="https://velog.velcdn.com/images/hyeonju_jo/post/35281644-96a0-4e09-9f6a-22aed7b7850c/image.png" alt=""></p>
</li>
<li><p>cmd 입력 후 엔터
<img src="https://velog.velcdn.com/images/hyeonju_jo/post/37f3fbde-e123-4b8d-8006-93b06c00f315/image.png" alt=""></p>
</li>
<li><p>해당 경로에 cmd 창이 나옵니다.</p>
</li>
<li><p>cmd창에서 cd를 이용하여 경로설정도 가능</p>
</li>
</ol>
<h2 id="환경-변수-설정">환경 변수 설정</h2>
<ol>
<li><p>윈도우 검색 창에 &#39;환경 변수&#39; 검색
<img src="https://velog.velcdn.com/images/hyeonju_jo/post/8cf57af7-0512-49cf-bac8-9a7d4090025f/image.png" alt=""></p>
</li>
<li><p>시스템 속성에서 &#39;환경 변수&#39; 클릭
<img src="https://velog.velcdn.com/images/hyeonju_jo/post/4c062342-91bb-46d1-a4f8-60997e220e8c/image.png" alt=""></p>
</li>
<li><p>시스템 변수 -&gt; Path 선택 후 편집 클릭
<img src="https://velog.velcdn.com/images/hyeonju_jo/post/7ee53dab-8315-4609-9a85-82eee3867fb8/image.png" alt=""></p>
</li>
<li><p>새로만들기 클릭 후 bin폴더 경로 입력 후 확인
<img src="https://velog.velcdn.com/images/hyeonju_jo/post/3653918b-31c0-4cc8-8973-319d3c6fda02/image.png" alt=""></p>
</li>
<li><p>나머지 창들도 확인 눌러서 적용</p>
</li>
</ol>
<h2 id="설치-확인">설치 확인</h2>
<p>cmd창에서 ffmpeg 입력 후 사진처럼 뜬다면 완료!</p>
<p><img src="https://velog.velcdn.com/images/hyeonju_jo/post/29361db4-48e1-46e8-ac6c-d59e24342e49/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Windows API] ShellExecute]]></title>
            <link>https://velog.io/@hyeonju_jo/Windows-API-ShellExecute</link>
            <guid>https://velog.io/@hyeonju_jo/Windows-API-ShellExecute</guid>
            <pubDate>Wed, 10 Jan 2024 06:17:09 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/hyeonju_jo/post/247edeea-e3a4-40f9-8985-6d7d33251f4f/image.png" alt=""></p>
<blockquote>
<p><strong>ShellExecute</strong> 함수는 Windows API로, Microsoft Windows 운영체제에서 외부 프로그램 또는 파일을 실행하는 데 사용되는 함수</p>
</blockquote>
<ul>
<li>함수는 주어진 파일을 실행하는 데 필요한 프로그램을 찾아서 실행하거나, 웹 페이지를 열고 특정 URL을 브라우저로 연결하는 데 사용된다.</li>
</ul>
<h1 id="shellexecute-함수-원형">ShellExecute 함수 원형</h1>
<pre><code>HINSTANCE ShellExecute(
  HWND hwnd,
  LPCTSTR lpOperation,
  LPCTSTR lpFile,
  LPCTSTR lpParameters,
  LPCTSTR lpDirectory,
  INT nShowCmd
);
</code></pre><h1 id="shellexecute의-주요-기능">ShellExecute의 주요 기능</h1>
<h3 id="파일-열기">파일 열기</h3>
<ul>
<li><strong>사용자의 시스템에 연결된 기본 프로그램을 사용하여 파일을 연다.</strong></li>
<li>예를 들어, PDF 파일을 열 경우 기본 PDF 뷰어가 실행된다.<h3 id="url-열기">URL 열기</h3>
</li>
<li><strong>기본 웹 브라우저에서 URL을 연다.</strong><h3 id="프로그램-실행">프로그램 실행</h3>
</li>
<li><strong>특정 프로그램을 실행한다.</strong><h3 id="시스템-명령-수행">시스템 명령 수행</h3>
</li>
<li><strong>&#39;explore&#39;, &#39;find&#39;, &#39;print&#39;와 같은 명령을 수행하여 파일 탐색기를 열거나, 파일을 검색하거나, 문서를 인쇄할 수 있다.</strong></li>
</ul>
<h1 id="shellexecute-parameter">ShellExecute Parameter</h1>
<p><strong>ShellExecute</strong>는 다양한 파라미터를 받을 수 있으며, 이 파라미터들은 함수의 동작 방식을 결정한다.</p>
<h4 id="1-hwnd">1. hwnd</h4>
<ul>
<li><strong>실행된 프로그램의 부모 윈도우 핸들</strong></li>
<li>인자를 사용하면 실행된 프로그램이 모달 대화 상자와 같은 모달 윈도우로 표시될 때 부모 윈도우를 지정할 수 있다.</li>
<li>일반적으로 NULL 값을 사용하거나 부모 윈도우의 핸들을 전달한다.</li>
<li>윈도우 핸들은 &#39;0&#39; 이다.<h4 id="2-lpoperation">2. lpOperation</h4>
</li>
<li><strong>실행할 작업을 나타내는 문자열</strong></li>
<li>주요 작업으로 &quot;open&quot;이나 &quot;print&quot;을 사용한다.</li>
<li>&quot;open&quot;은 파일을 실행하는 작업을 의미하고, &quot;print&quot;는 파일을 인쇄하는 작업을 의미 한다.</li>
<li>NULL을 지정하면 파일의 기본 동작(대부분 &quot;open&quot;)이 수행된다.<h4 id="3-lpfile">3. lpFile</h4>
</li>
<li><strong>실행할 파일의 경로 또는 실행할 프로그램의 이름</strong><h4 id="4-lpparameters">4. lpParameters</h4>
</li>
<li><strong>실행될(lpFile에 지정된) 프로그램에 전달할 추가 매개변수</strong><h4 id="5-lpdirectory">5. lpDirectory</h4>
</li>
<li><strong>실행될 프로그램의 기본 작업 디렉토리</strong></li>
<li>실행될 프로그램의 작업 디렉토리를 지정할 수 있다.<h4 id="6-nshowcmd">6. nShowCmd</h4>
</li>
<li><strong>실행될 프로그램의 창을 어떻게 표시할지를 지정하는 정수</strong></li>
<li>주요 값으로 SW_SHOWNORMAL, SW_SHOWMAXIMIZED, SW_SHOWMINIMIZED 등이 있다.</li>
</ul>
<h1 id="shellexecute-예시">ShellExecute 예시</h1>
<h3 id="delphi">Delphi</h3>
<pre><code>uses
  ShellAPI;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShellExecute(Handle, &#39;open&#39;, &#39;C:\example.txt&#39;, nil, nil, SW_SHOWNORMAL);
end;</code></pre><h3 id="c">C++</h3>
<pre><code class="language-cpp">#include &lt;windows.h&gt;

int main() {
    ShellExecute(NULL, &quot;open&quot;, &quot;http://www.example.com&quot;, NULL, NULL, SW_SHOWNORMAL);
    return 0;
}</code></pre>
<h1 id="반환-값">반환 값</h1>
<ul>
<li><strong>ShellExecute</strong>는 <strong>HINSTANCE</strong>를 반환한다.</li>
<li>값이 32보다 크면 성공, 그렇지 않으면 오류를 나타낸다.</li>
<li>오류 코드를 얻으려면 GetLastError 함수를 사용할 수 있습니다.</li>
</ul>
<h2 id="hinstance">HINSTANCE</h2>
<ul>
<li><strong>HINSTANCE</strong>는 Windows 프로그래밍에서 사용되는 핸들 타입</li>
<li>ShellExecute 함수에서 반환되는 HINSTANCE 값은 호출된 작업의 성공 여부 및 관련 정보를 나타내는 데 사용된다.</li>
</ul>
<h3 id="hinstance의-의미">HINSTANCE의 의미</h3>
<h4 id="성공여부">성공여부</h4>
<p>ShellExecute가 성공적으로 수행되었다면, 반환되는 <strong>HINSTANCE 값은 32보다 크다.</strong>
이 경우, HINSTANCE는 실행된 프로그램이나 문서의 인스턴스 핸들을 의미합니다.</p>
<h4 id="오류코드">오류코드</h4>
<ul>
<li><strong>만약 반환된 값이 32 이하라면, 이는 오류를 나타낸다.</strong></li>
</ul>
<table>
<thead>
<tr>
<th>코드</th>
<th align="center">값</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>ERROR_FILE_NOT_FOUND</strong></td>
<td align="center">2</td>
<td>지정된 파일을 찾을 수 없습니다.</td>
</tr>
<tr>
<td><strong>ERROR_PATH_NOT_FOUND</strong></td>
<td align="center">3</td>
<td>지정된 경로를 찾을 수 없습니다.</td>
</tr>
<tr>
<td><strong>ERROR_BAD_FORMAT</strong></td>
<td align="center">11</td>
<td>실행 파일이 손상되었거나 유효하지 않은                                      실행파일 입니다.</td>
</tr>
<tr>
<td><strong>SE_ERR_ACCESSDENIED</strong></td>
<td align="center">5</td>
<td>지정된 파일에 대한 접근이 거부되었습니                                     다.</td>
</tr>
<tr>
<td><strong>SE_ERR_ASSOCINCOMPLETE</strong></td>
<td align="center">27</td>
<td>파일 연결이 완전하지 않습니다.</td>
</tr>
<tr>
<td><strong>SE_ERR_DDEBUSY</strong></td>
<td align="center">30</td>
<td>DDE 트랜잭션이 다른 것에 의해 사용 중                                     입니다.</td>
</tr>
<tr>
<td><strong>SE_ERR_DDEFAIL</strong></td>
<td align="center">29</td>
<td>DDE 트랜잭션이 실패했습니다.</td>
</tr>
<tr>
<td><strong>SE_ERR_DDETIMEOUT</strong></td>
<td align="center">28</td>
<td>DDE 트랜잭션에 요청 시간이 초과되었습                                        니다.</td>
</tr>
<tr>
<td><strong>SE_ERR_NOASSOC</strong></td>
<td align="center">31</td>
<td>주어진 파일 이름 확장명에 연결된 응용                                        프로그램이 없습니다.</td>
</tr>
<tr>
<td><strong>SE_ERR_SHARE</strong></td>
<td align="center">26</td>
<td>공유 위반 오류가 발생했습니다.</td>
</tr>
</tbody></table>
<h3 id="hinstance-사용-예제">HINSTANCE 사용 예제</h3>
<h4 id="delphi-1">Delphi</h4>
<pre><code>uses
  ShellAPI;

procedure OpenURL;
var
  H: HINST;
begin
  H := ShellExecute(0, &#39;open&#39;, &#39;http://www.example.com&#39;, nil, nil, SW_SHOWNORMAL);
  if H &lt;= 32 then
    ShowMessage(&#39;Error opening URL&#39;);
end;
</code></pre><h4 id="c-1">C++</h4>
<pre><code class="language-cpp">#include &lt;windows.h&gt;
#include &lt;shellapi.h&gt;

int main() {
    HINSTANCE hInst = ShellExecute(NULL, &quot;open&quot;, &quot;http://www.example.com&quot;, NULL, NULL, SW_SHOWNORMAL);
    if ((int)hInst &lt;= 32) {
        // 오류 처리
    }
    return 0;
}</code></pre>
<h1 id="shellexecute-사용시-주의할-점">ShellExecute 사용시 주의할 점</h1>
<ul>
<li><strong>ShellExecute</strong>를 사용할 때는 보안에 특별히 주의해야한다.</li>
<li>사용자로부터 입력받은 데이터를 이 함수에 직접 전달하는 경우, 악의적인 입력으로 인해 보안 취약점이 발생할 수 있다.</li>
<li>따라서, 사용자 입력을 사용하여 ShellExecute를 호출할 때는 해당 입력을 철저히 검증해야 합니다.</li>
</ul>
<hr>
<h1 id="참조">참조</h1>
<p><a href="https://learn.microsoft.com/ko-kr/windows/win32/shell/launch">애플리케이션 시작(ShellExecute, ShellExecuteEx, SHELLEXECUTEINFO)</a></p>
]]></description>
        </item>
    </channel>
</rss>